feat(docs): generate developer docs with rustdoc

This commit is contained in:
Phil Booth 2018-07-03 18:13:43 +01:00
Родитель fb56a2090b
Коммит f2edb78c79
26 изменённых файлов: 353 добавлений и 38 удалений

Просмотреть файл

@ -4,11 +4,11 @@ version = "1.115.0"
publish = false
[[bin]]
name = "fxa-email-service"
name = "fxa_email_send"
path = "src/bin/service.rs"
[[bin]]
name = "fxa-email-queues"
name = "fxa_email_queues"
path = "src/bin/queues.rs"
[dependencies]

Просмотреть файл

@ -16,8 +16,8 @@ RUN \
cargo build --release && \
cp -R /app/config/* /app/bin/config && \
cp /app/Rocket.toml /app/bin && \
cp /app/target/release/fxa-email-service /app/bin && \
cp /app/target/release/fxa-email-queues /app/bin
cp /app/target/release/fxa_email_send /app/bin && \
cp /app/target/release/fxa_email_queues /app/bin
FROM debian:stretch-slim
@ -38,4 +38,4 @@ USER app
ENV ROCKET_ENV production
CMD ["/app/bin/fxa-email-service"]
CMD ["/app/bin/fxa_email_send"]

Просмотреть файл

@ -1,4 +1,4 @@
# fxa-email-service
# fxa_email_service
[![Build status](https://img.shields.io/travis/mozilla/fxa-email-service.svg?style=flat-square)](https://travis-ci.org/mozilla/fxa-email-service)
[![CircleCI](https://circleci.com/gh/mozilla/fxa-email-service/tree/master.svg?style=svg)](https://circleci.com/gh/mozilla/fxa-email-service/tree/master)
@ -194,7 +194,7 @@ Once you have config set,
you can start the service with:
```
cargo r --bin fxa-email-service
cargo r --bin fxa_email_send
```
Then you can use `curl`
@ -228,7 +228,7 @@ or in `config/local.json`:
Then start the service:
```
cargo r --bin fxa-email-service
cargo r --bin fxa_email_send
```
Then set `provider` to `sendgrid` in your request payload:
@ -308,5 +308,5 @@ to the main email-sending service.
You can run it locally like so:
```
cargo r --bin fxa-email-queues
cargo r --bin fxa_email_queues
```

2
r
Просмотреть файл

@ -1 +1 @@
scripts/run_service.sh
scripts/run_send.sh

Просмотреть файл

@ -1,3 +1,3 @@
#!/bin/sh
cargo run --bin fxa-email-queues
cargo run --bin fxa_email_queues

3
scripts/run_send.sh Executable file
Просмотреть файл

@ -0,0 +1,3 @@
#!/bin/sh
cargo run --bin fxa_email_send

Просмотреть файл

@ -1,3 +0,0 @@
#!/bin/sh
cargo run --bin fxa-email-service

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Error definitions.
use std::{fmt, result};
use failure::{Backtrace, Context, Fail};
@ -22,6 +24,14 @@ mod test;
pub type AppResult<T> = result::Result<T, AppError>;
/// The main error type
/// returned by this service.
///
/// Error responses are serialised with a JSON body
/// that honours the same format
/// used by other FxA services:
///
/// `{ code, error, errno, message }`
#[derive(Debug)]
pub struct AppError {
inner: Context<AppErrorKind>,

Просмотреть файл

@ -2,6 +2,20 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Strongly-typed wrapper
//! for a subset of [`fxa-auth-db-mysql`][authdb].
//!
//! Ultimately we will move away
//! from the auth db
//! so, to avoid unnecessary coupling,
//! this module MUST NOT be used directly.
//! Instead,
//! all access should be via
//! [`bounces::Bounces`][bounces].
//!
//! [authdb]: https://github.com/mozilla/fxa-auth-db-mysql/
//! [bounces]: ../bounces/struct.Bounces.html
use std::fmt::Debug;
use hex;

Просмотреть файл

@ -2,6 +2,12 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! The queue-processing loop for fxa_email_service.
//!
//! Configuration is via [`settings::Settings`][settings].
//!
//! [settings]: ../fxa_email_service/settings/struct.Settings.html
extern crate futures;
extern crate fxa_email_service;
#[macro_use]

Просмотреть файл

@ -2,6 +2,15 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! The main process for fxa-email-service.
//! Starts a Rocket server
//! that exposes one endpoint: `POST /send`
//!
//! Configuration is via [`settings::Settings`][settings].
//! By default the server listens on `127.0.0.1:8001`.
//!
//! [settings]: ../fxa_email_service/settings/struct.Settings.html
#![feature(plugin)]
#![plugin(rocket_codegen)]
@ -46,7 +55,7 @@ fn main() {
let log =
MozlogLogger::with_request(request).expect("MozlogLogger::with_request error");
if response.status().code == 200 {
slog_info!(log, "{}", "Request finished succesfully.";
slog_info!(log, "{}", "Request finished succesfully.";
"status_code" => response.status().code, "status_msg" => response.status().reason);
}
}))

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Bounce and complaint handling.
use std::{collections::HashMap, time::SystemTime};
use app_errors::{AppErrorKind, AppResult};
@ -12,6 +14,14 @@ use settings::{BounceLimit, BounceLimits, Settings};
#[cfg(test)]
mod test;
/// Bounce/complaint registry.
///
/// Currently just a nicer abstraction
/// over the `emailBounces` table
/// in `fxa-auth-db-mysql`,
/// but longer-term we'll migrate
/// to something specifically tailored
/// for this service.
#[derive(Debug)]
pub struct Bounces<D: Db> {
db: D,
@ -22,6 +32,7 @@ impl<D> Bounces<D>
where
D: Db,
{
/// Instantiate the registry.
pub fn new(settings: &Settings, db: D) -> Bounces<D> {
Bounces {
db,
@ -29,6 +40,15 @@ where
}
}
/// Check an email address
/// against bounce/complaint records
/// from the registry.
///
/// If matching records are found,
/// they are checked against thresholds
/// defined in the [`BounceLimits` setting][limits].
///
/// [limits]: ../settings/struct.BounceLimits.html
pub fn check(&self, address: &str) -> AppResult<()> {
let bounces = self.db.get_bounces(address)?;
let now = SystemTime::now()
@ -69,6 +89,8 @@ where
.map(|_| ())
}
/// Record a hard or soft bounce
/// against an email address.
pub fn record_bounce(
&self,
address: &str,
@ -80,6 +102,8 @@ where
Ok(())
}
/// Record a complaint
/// against an email address.
pub fn record_complaint(
&self,
address: &str,

Просмотреть файл

@ -2,6 +2,9 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Deserialization functions
//! for use with serde's `deserialize_with` attribute.
use std::convert::TryFrom;
use serde::de::{Deserialize, Deserializer, Error, Unexpected};
@ -12,6 +15,7 @@ use validate;
#[cfg(test)]
mod test;
/// Validate and deserialize an AWS region.
pub fn aws_region<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,
@ -19,6 +23,7 @@ where
deserialize(deserializer, validate::aws_region, "AWS region")
}
/// Validate and deserialize an AWS access key.
pub fn aws_access<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,
@ -26,6 +31,7 @@ where
deserialize(deserializer, validate::aws_access, "AWS access key")
}
/// Validate and deserialize an AWS secret key.
pub fn aws_secret<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,
@ -33,6 +39,7 @@ where
deserialize(deserializer, validate::aws_secret, "AWS secret key")
}
/// Validate and deserialize a base URI.
pub fn base_uri<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,
@ -40,6 +47,7 @@ where
deserialize(deserializer, validate::base_uri, "base URI")
}
/// Validate and deserialize an email address.
pub fn email_address<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,
@ -48,6 +56,7 @@ where
Ok(email.to_lowercase())
}
/// Validate and deserialize a duration.
pub fn duration<'d, D>(deserializer: D) -> Result<u64, D::Error>
where
D: Deserializer<'d>,
@ -58,6 +67,7 @@ where
.map_err(|_| D::Error::invalid_value(Unexpected::Str(&value), &"duration"))
}
/// Validate and deserialize a host name or IP address.
pub fn host<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,
@ -65,6 +75,7 @@ where
deserialize(deserializer, validate::host, "host name or IP address")
}
/// Validate and deserialize a provider name.
pub fn provider<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,
@ -72,6 +83,7 @@ where
deserialize(deserializer, validate::provider, "'ses' or 'sendgrid'")
}
/// Validate and deserialize a sender name.
pub fn sender_name<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,
@ -79,6 +91,7 @@ where
deserialize(deserializer, validate::sender_name, "sender name")
}
/// Validate and deserialize a Sendgrid API key.
pub fn sendgrid_api_key<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,
@ -86,6 +99,7 @@ where
deserialize(deserializer, validate::sendgrid_api_key, "Sendgrid API key")
}
/// Validate and deserialize an AWS SQS URL.
pub fn sqs_url<'d, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'d>,

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Maps duration strings to millisecond values.
use std::{
convert::{From, TryFrom},
error::Error,
@ -28,6 +30,7 @@ lazy_static! {
Regex::new("^(?:([0-9]+) )?(second|minute|hour|day|week|month|year)s?$").unwrap();
}
/// The error type returned by `Duration::try_from`.
#[derive(Debug)]
pub struct DurationError {
pub value: String,
@ -45,6 +48,14 @@ impl Display for DurationError {
}
}
/// A duration type
/// represented in milliseconds,
/// for compatibility with
/// the rest of the FxA ecosystem.
///
/// Can be deserialized from duration strings
/// of the format `"{number} {period}"`,
/// e.g. `"1 hour"` or `"10 minutes"`.
#[derive(Debug, PartialEq)]
pub struct Duration(u64);

Просмотреть файл

@ -2,6 +2,28 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! These are the developer docs
//! for the Firefox Accounts email-sending service.
//! For higher-level documentation,
//! see the [readme].
//!
//! The project is compiled as a library
//! that is linked against by
//! two separate binaries:
//!
//! * [`fxa_email_send`][send] runs a Rocket server
//! exposing an endpoint that enables callers
//! to send email.
//!
//! * [`fxa_email_queues`][queues] runs a process
//! that loops infinitely,
//! polling SQS queues for
//! SES bounce, complaint and delivery notifications.
//!
//! [readme]: https://github.com/mozilla/fxa-email-service/blob/master/README.md#fxa_email_service
//! [send]: ../fxa_email_send/index.html
//! [queues]: ../fxa_email_queues/index.html
#![feature(assoc_unix_epoch)]
#![feature(plugin)]
#![feature(try_from)]

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Mozlog-compatible logging.
use std::{io, ops::Deref};
use failure::{err_msg, Error};
@ -65,9 +67,11 @@ impl Value for Settings {
}
}
/// Mozlog-compatible logger type.
pub struct MozlogLogger(slog::Logger);
impl MozlogLogger {
/// Construct a logger.
pub fn new(settings: &Settings) -> Result<MozlogLogger, Error> {
let logger = match &*settings.logging {
"mozlog" => {
@ -92,6 +96,7 @@ impl MozlogLogger {
Ok(MozlogLogger(logger?))
}
/// Log a rocket request.
pub fn with_request(request: &Request) -> Result<MozlogLogger, Error> {
let logger = request
.guard::<State<MozlogLogger>>()

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Temporary storage for message metadata.
use std::{
error::Error,
fmt::{self, Display, Formatter},
@ -16,6 +18,15 @@ use settings::Settings;
#[cfg(test)]
mod test;
/// Message data store.
///
/// Currently uses Redis
/// under the hood,
/// although that may not
/// always be the case.
///
/// Data is keyed by
/// a hash of the message id.
#[derive(Debug)]
pub struct MessageData {
client: RedisClient,
@ -23,6 +34,7 @@ pub struct MessageData {
}
impl MessageData {
/// Instantiate a storage client.
pub fn new(settings: &Settings) -> MessageData {
MessageData {
client: RedisClient::open(
@ -32,6 +44,11 @@ impl MessageData {
}
}
/// Consume (read and delete) message metadata.
///
/// This is a destructive operation.
/// Once consumed,
/// the data is permanently destroyed.
pub fn consume(&self, message_id: &str) -> Result<String, MessageDataError> {
let key = self.generate_key(message_id)?;
let key_str = key.as_str();
@ -44,6 +61,10 @@ impl MessageData {
.map_err(From::from)
}
/// Store message metadata.
///
/// Any data previously stored for the message id
/// will be replaced.
pub fn set(&self, message_id: &str, metadata: &str) -> Result<(), MessageDataError> {
let key = self.generate_key(message_id)?;
self.client.set(key.as_str(), metadata).map_err(From::from)
@ -56,6 +77,7 @@ impl MessageData {
}
}
/// The error type returned by `MessageData` methods.
#[derive(Debug)]
pub struct MessageDataError {
description: String,

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Generic abstraction of specific email providers.
use std::{boxed::Box, collections::HashMap};
use self::{
@ -14,6 +16,7 @@ mod mock;
mod sendgrid;
mod ses;
/// Email headers.
pub type Headers = HashMap<String, String>;
trait Provider {
@ -28,12 +31,14 @@ trait Provider {
) -> AppResult<String>;
}
/// Generic provider wrapper.
pub struct Providers {
default_provider: String,
providers: HashMap<String, Box<Provider>>,
}
impl Providers {
/// Instantiate the provider clients.
pub fn new(settings: &Settings) -> Providers {
let mut providers: HashMap<String, Box<Provider>> = HashMap::new();
@ -53,6 +58,7 @@ impl Providers {
}
}
/// Send an email via an underlying provider.
pub fn send(
&self,
to: &str,

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Queue-processing abstractions.
use std::{
boxed::Box,
error::Error,
@ -24,6 +26,7 @@ pub mod sqs;
#[cfg(test)]
mod test;
/// Top-level queue wrapper.
#[derive(Debug)]
pub struct Queues {
bounce_queue: Box<Incoming>,
@ -34,6 +37,7 @@ pub struct Queues {
message_data: MessageData,
}
/// An incoming bounce/complaint queue.
pub trait Incoming: Debug + Sync {
fn receive(&'static self) -> ReceiveFuture;
fn delete(&'static self, message: Message) -> DeleteFuture;
@ -42,27 +46,34 @@ pub trait Incoming: Debug + Sync {
type ReceiveFuture = Box<Future<Item = Vec<Message>, Error = QueueError>>;
type DeleteFuture = Box<Future<Item = (), Error = QueueError>>;
/// An outgoing notification queue.
pub trait Outgoing: Debug + Sync {
fn send(&'static self, body: &Notification) -> SendFuture;
}
type SendFuture = Box<Future<Item = String, Error = QueueError>>;
/// A queue factory.
pub trait Factory {
fn new(id: String, settings: &Settings) -> Self;
}
/// Generic message type.
#[derive(Debug, Default)]
pub struct Message {
pub id: String,
pub notification: Notification,
}
/// The error type returned by queue methods.
#[derive(Debug)]
pub struct QueueError {
description: String,
}
/// Queue "ids"
/// (which is really just a generic name
/// for SQS queue URLs).
#[derive(Debug)]
pub struct QueueIds {
pub bounce: String,
@ -72,6 +83,7 @@ pub struct QueueIds {
}
impl Queues {
/// Instantiate the queue clients.
pub fn new<Q: 'static>(ids: QueueIds, settings: &Settings) -> Queues
where
Q: Incoming + Outgoing + Factory,
@ -86,6 +98,7 @@ impl Queues {
}
}
/// Poll all queues and handle any notifications.
pub fn process(&'static self) -> QueueFuture {
let joined_futures = self
.process_queue(&self.bounce_queue)

Просмотреть файл

@ -2,18 +2,27 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Generic queue notification types.
use chrono::{DateTime, Utc};
pub use super::sqs::notification::{
BounceSubtype, BounceType, ComplaintFeedbackType, Header, HeaderValue, NotificationType,
};
// This "generic" notification type is actually just a subset of the SQS
// notification type in src/queues/sqs/notification/mod.rs. That's mostly
// so we can easily interface with existing auth server code that already
// knows about the SQS message format. Longer-term we can do whatever we
// want in here.
/// The root notification type.
///
/// This "generic" type
/// is really just a subset
/// of the [SQS notification type][sqs].
/// That's mostly so we can easily interface
/// with existing auth server code
/// that already knows about
/// the SQS message format.
/// Longer-term we can do whatever we want
/// in here.
///
/// [sqs]: ../sqs/notification/struct.Notification.html
#[derive(Debug, Default, Serialize)]
pub struct Notification {
#[serde(rename = "notificationType")]

Просмотреть файл

@ -2,6 +2,9 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Concrete trait implementations
//! for AWS SQS queues.
use std::{
boxed::Box,
fmt::{self, Debug, Formatter},
@ -26,6 +29,7 @@ use settings::Settings;
pub mod notification;
/// An AWS SQS queue type.
pub struct Queue {
client: Box<Sqs>,
url: String,

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! SQS queue notification types.
use std::fmt::{self, Display, Formatter};
use chrono::{DateTime, Utc};
@ -19,19 +21,22 @@ use auth_db::{BounceSubtype as AuthDbBounceSubtype, BounceType as AuthDbBounceTy
#[cfg(test)]
mod test;
// This module is a direct encoding of the SES notification format documented
// here:
//
// https://docs.aws.amazon.com/ses/latest/DeveloperGuide/notification-contents.html
//
// It also receives synthesized events from our Sendgrid event proxy:
//
// https://github.com/mozilla/fxa-sendgrid-event-proxy
//
// Because we don't have all of the data to fill out an entire Notification
// struct with the data that Sendgrid provides, many of the fields which are
// not optional in the spec are Option-wrapped anyway.
/// The root SQS queue notification type.
///
/// This type is a direct encoding
/// of the [SES notification format][format].
///
/// It also receives synthesized notifications
/// from our [Sendgrid event proxy][proxy].
/// Because we don't have all of the data
/// necessary to fill out an entire `Notification`
/// from the data that Sendgrid provides,
/// many of the fields
/// which are not optional in the spec
/// are `Option`-wrapped anyway.
///
/// [format]: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/notification-contents.html
/// [proxy]: https://github.com/mozilla/fxa-sendgrid-event-proxy
#[derive(Debug, Deserialize)]
pub struct Notification {
#[serde(rename = "notificationType")]

Просмотреть файл

@ -2,6 +2,9 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Route handler
//! for the `POST /send` endpoint.
use rocket::{
data::{self, FromData},
http::Status,

Просмотреть файл

@ -2,11 +2,18 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Serialization functions
//! for use with serde's `serialize_with` attribute.
use serde::ser;
#[cfg(test)]
mod test;
/// Serialize an `Option`
/// containing sensitive data
/// to either of the strings
/// `"[hidden]"` or `"[not set]"`.
pub fn hidden_or_not_set<T, S>(ref item: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,

Просмотреть файл

@ -2,6 +2,8 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Application settings.
use std::env;
use config::{Config, ConfigError, Environment, File};
@ -13,92 +15,200 @@ use serialize;
#[cfg(test)]
mod test;
/// Settings related to `fxa-auth-db-mysql`,
/// which is used to store
/// bounce, complaint and delivery notifications.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct AuthDb {
/// The base URI for the `fxa-auth-db-mysql` instance.
#[serde(deserialize_with = "deserialize::base_uri")]
pub baseuri: String,
}
/// Settings for AWS.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Aws {
/// Controls the access and secret keys for connecting to AWS.
#[serde(serialize_with = "serialize::hidden_or_not_set")]
pub keys: Option<AwsKeys>,
/// The AWS region for SES and SQS.
#[serde(deserialize_with = "deserialize::aws_region")]
pub region: String,
/// URLs for SQS queues.
pub sqsurls: Option<SqsUrls>,
}
/// AWS keys.
/// These are sensitive data
/// and will not be logged.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct AwsKeys {
/// The AWS access key.
#[serde(deserialize_with = "deserialize::aws_access")]
pub access: String,
/// The AWS secret key.
#[serde(deserialize_with = "deserialize::aws_secret")]
pub secret: String,
}
/// A definition object for a bounce/complaint limit.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct BounceLimit {
/// The time period
/// within which to limit bounces/complaints.
/// Deserialized from a string
/// of the format `"{number} {period}"`,
/// e.g. `"1 hour"` or `"10 minutes"`.
#[serde(deserialize_with = "deserialize::duration")]
pub period: u64,
/// The maximum number of bounces/complaints
/// to permit within the specified time period.
pub limit: u8,
}
/// Controls the thresholds and behaviour
/// for bounce and complaint reports.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct BounceLimits {
/// Controls whether to enable bounce limits.
/// If set to `false`,
/// bounce and complaint records in the database
/// are ignored.
pub enabled: bool,
/// Limits for complaints/spam reports.
pub complaint: Vec<BounceLimit>,
/// Limits for hard (permanent) bounces.
pub hard: Vec<BounceLimit>,
/// Limits for soft (transient) bounces.
pub soft: Vec<BounceLimit>,
}
/// Settings for Redis.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Redis {
/// The host name or IP address.
#[serde(deserialize_with = "deserialize::host")]
pub host: String,
/// TCP port number.
pub port: u16,
}
/// Controls the name and email address
/// that are used for the `From` and `Sender`
/// email headers.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Sender {
/// The email address.
#[serde(deserialize_with = "deserialize::email_address")]
pub address: String,
/// The name
/// (may contain spaces).
#[serde(deserialize_with = "deserialize::sender_name")]
pub name: String,
}
/// Settings for Sendgrid.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Sendgrid {
/// The API key.
/// This is sensitive data
/// and will not be logged.
#[serde(deserialize_with = "deserialize::sendgrid_api_key")]
pub key: String,
}
/// URLs for SQS queues.
/// Note that these are separate queues right now
/// for consistency with the auth server.
/// Long term,
/// there is nothing preventing us
/// from handling all incoming notification types
/// with a single queue.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct SqsUrls {
// Queue URLs are specified here for consistency with the auth server.
// However, we could also store queue names instead and then fetch the
// URL with rusoto_sqs::GetQueueUrl. Then we might be allowed to include
// the production queue names in default config?
/// The incoming bounce queue URL.
///
/// Queue URLs are specified here
/// for consistency with the auth server.
/// However, we could also store queue names instead
/// and then fetch the URL with rusoto_sqs::GetQueueUrl.
/// Then we might be allowed to include
/// the production queue names in default config?
#[serde(deserialize_with = "deserialize::sqs_url")]
pub bounce: String,
/// The incoming complaint queue URL.
#[serde(deserialize_with = "deserialize::sqs_url")]
pub complaint: String,
/// The incoming delivery queue URL.
#[serde(deserialize_with = "deserialize::sqs_url")]
pub delivery: String,
/// The outgoing notification queue URL,
/// used to forward notifications
/// for additional processing by callers.
#[serde(deserialize_with = "deserialize::sqs_url")]
pub notification: String,
}
/// The root settings object.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Settings {
/// Settings related to `fxa-auth-db-mysql`,
/// which is used to store
/// bounce, complaint and delivery notifications.
pub authdb: AuthDb,
/// Settings for AWS,
/// including region, access keys
/// and URLs for SQS queues.
pub aws: Aws,
/// Controls the thresholds and behaviour
/// for bounce and complaint reports.
/// If bounce limits are enabled,
/// emails sent to offending addresses
/// will fail with a `429` error.
pub bouncelimits: BounceLimits,
/// The HMAC key to use internally
/// for hashing message ids.
/// This is sensitive data
/// and will not be logged.
pub hmackey: String,
/// The logging format to use,
/// can be `"mozlog"`, `"pretty"` or `"null"`.
pub logging: String,
/// The default email provider to use,
/// can be `"ses"`, `"sendgrid"` or `"mock"`.
/// Note that this setting can be overridden
/// on a per-request basis.
#[serde(deserialize_with = "deserialize::provider")]
pub provider: String,
/// Settings for Redis,
/// which is used to store metadata
/// associated with a message.
pub redis: Redis,
/// Controls the name and email address
/// that are used for the `From` and `Sender`
/// email headers.
pub sender: Sender,
/// Settings for Sendgrid.
#[serde(serialize_with = "serialize::hidden_or_not_set")]
pub sendgrid: Option<Sendgrid>,
}

Просмотреть файл

@ -2,6 +2,17 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//! Common validation logic.
//!
//! All functions are predicates,
//! returning `true` if a value is valid
//! and `false` if it isn't.
//! Note that the intention is not to provide
//! perfect validation in each case.
//! Mostly it is to rule out obvious mistakes
//! when setting values in config
//! or wiring in request parameters.
use regex::Regex;
use rusoto_core::Region;
@ -26,42 +37,52 @@ lazy_static! {
Regex::new("^https://sqs\\.[a-z0-9-]+\\.amazonaws\\.com/[0-9]+/[A-Za-z0-9-]+$").unwrap();
}
/// Validate an AWS region.
pub fn aws_region(value: &str) -> bool {
value.parse::<Region>().is_ok()
}
/// Validate an AWS access key.
pub fn aws_access(value: &str) -> bool {
AWS_ACCESS_FORMAT.is_match(value)
}
/// Validate an AWS secret key.
pub fn aws_secret(value: &str) -> bool {
AWS_SECRET_FORMAT.is_match(value)
}
/// Validate a base URI.
pub fn base_uri(value: &str) -> bool {
BASE_URI_FORMAT.is_match(value)
}
/// Validate an email address.
pub fn email_address(value: &str) -> bool {
value.len() < 254 && EMAIL_ADDRESS_FORMAT.is_match(value)
}
/// Validate a host name or IP address.
pub fn host(value: &str) -> bool {
HOST_FORMAT.is_match(value)
}
/// Validate an email provider.
pub fn provider(value: &str) -> bool {
PROVIDER_FORMAT.is_match(value)
}
/// Validate a sender name.
pub fn sender_name(value: &str) -> bool {
SENDER_NAME_FORMAT.is_match(value)
}
/// Validate a Sendgrid API key.
pub fn sendgrid_api_key(value: &str) -> bool {
SENDGRID_API_KEY_FORMAT.is_match(value)
}
/// Validate an AWS SQS URL.
pub fn sqs_url(value: &str) -> bool {
SQS_URL_FORMAT.is_match(value)
}