You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Split the service in multiple crates
This commit is contained in:
74
Cargo.lock
generated
74
Cargo.lock
generated
@ -1355,22 +1355,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
|
||||
name = "mas-cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
"anyhow",
|
||||
"argon2",
|
||||
"clap",
|
||||
"dotenv",
|
||||
"hyper",
|
||||
"indoc",
|
||||
"mas-config",
|
||||
"mas-core",
|
||||
"schemars",
|
||||
"serde_yaml",
|
||||
"tokio",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"warp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||
name = "mas-config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"elliptic-curve",
|
||||
"figment",
|
||||
"indoc",
|
||||
"jwt-compact",
|
||||
"k256",
|
||||
"pkcs8",
|
||||
"rand 0.8.4",
|
||||
"rsa",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"sqlx",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matrix-authentication-service"
|
||||
name = "mas-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
@ -1379,11 +1412,9 @@ dependencies = [
|
||||
"bincode",
|
||||
"chacha20poly1305",
|
||||
"chrono",
|
||||
"clap",
|
||||
"cookie",
|
||||
"crc",
|
||||
"data-encoding",
|
||||
"dotenv",
|
||||
"elliptic-curve",
|
||||
"figment",
|
||||
"futures-util",
|
||||
@ -1393,6 +1424,7 @@ dependencies = [
|
||||
"itertools",
|
||||
"jwt-compact",
|
||||
"k256",
|
||||
"mas-config",
|
||||
"mime",
|
||||
"oauth2-types",
|
||||
"password-hash",
|
||||
@ -1411,14 +1443,26 @@ dependencies = [
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
"warp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1"
|
||||
dependencies = [
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.9.1"
|
||||
|
@ -1,8 +1,5 @@
|
||||
[workspace]
|
||||
|
||||
members = [
|
||||
"oauth2-types",
|
||||
"matrix-authentication-service",
|
||||
]
|
||||
members = ["crates/*"]
|
||||
|
||||
resolver = "2"
|
||||
|
27
crates/cli/Cargo.toml
Normal file
27
crates/cli/Cargo.toml
Normal file
@ -0,0 +1,27 @@
|
||||
[package]
|
||||
name = "mas-cli"
|
||||
version = "0.1.0"
|
||||
authors = ["Quentin Gliech <quenting@element.io>"]
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.11.0", features = ["full"] }
|
||||
anyhow = "1.0.44"
|
||||
clap = "3.0.0-beta.4"
|
||||
tracing = "0.1.27"
|
||||
tracing-subscriber = "0.2.22"
|
||||
dotenv = "0.15.0"
|
||||
schemars = { version = "0.8.3", features = ["url", "chrono"] }
|
||||
tower = { version = "0.4.8", features = ["full"] }
|
||||
tower-http = { version = "0.1.1", features = ["full"] }
|
||||
hyper = { version = "0.14.12", features = ["full"] }
|
||||
serde_yaml = "0.8.21"
|
||||
warp = "0.3.1"
|
||||
argon2 = { version = "0.3.1", features = ["password-hash"] }
|
||||
|
||||
mas-config = { path = "../config" }
|
||||
mas-core = { path = "../core" }
|
||||
|
||||
[dev-dependencies]
|
||||
indoc = "1.0.3"
|
@ -13,11 +13,11 @@
|
||||
// limitations under the License.
|
||||
|
||||
use clap::Clap;
|
||||
use mas_config::{ConfigurationSection, RootConfig};
|
||||
use schemars::schema_for;
|
||||
use tracing::info;
|
||||
|
||||
use super::RootCommand;
|
||||
use crate::config::{ConfigurationSection, RootConfig};
|
||||
|
||||
#[derive(Clap, Debug)]
|
||||
pub(super) struct ConfigCommand {
|
@ -14,9 +14,10 @@
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::Clap;
|
||||
use mas_config::DatabaseConfig;
|
||||
use mas_core::storage::MIGRATOR;
|
||||
|
||||
use super::RootCommand;
|
||||
use crate::{config::DatabaseConfig, storage::MIGRATOR};
|
||||
|
||||
#[derive(Clap, Debug)]
|
||||
pub(super) struct DatabaseCommand {
|
@ -12,18 +12,22 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Clippy seems confused by clap.rs derive macros
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::all)]
|
||||
#![warn(clippy::pedantic)]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
#![allow(clippy::suspicious_else_formatting)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::Clap;
|
||||
use mas_config::ConfigurationSection;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
|
||||
|
||||
use self::{
|
||||
config::ConfigCommand, database::DatabaseCommand, manage::ManageCommand, server::ServerCommand,
|
||||
};
|
||||
use crate::config::ConfigurationSection;
|
||||
|
||||
mod config;
|
||||
mod database;
|
||||
@ -46,7 +50,7 @@ enum Subcommand {
|
||||
}
|
||||
|
||||
#[derive(Clap, Debug)]
|
||||
pub struct RootCommand {
|
||||
struct RootCommand {
|
||||
/// Path to the configuration file
|
||||
#[clap(short, long, global = true, default_value = "config.yaml")]
|
||||
config: PathBuf,
|
||||
@ -56,7 +60,7 @@ pub struct RootCommand {
|
||||
}
|
||||
|
||||
impl RootCommand {
|
||||
pub async fn run(&self) -> anyhow::Result<()> {
|
||||
async fn run(&self) -> anyhow::Result<()> {
|
||||
use Subcommand as S;
|
||||
match &self.subcommand {
|
||||
Some(S::Config(c)) => c.run(self).await,
|
||||
@ -71,3 +75,29 @@ impl RootCommand {
|
||||
T::load_from_file(&self.config).context("could not load configuration")
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
// Load environment variables from .env files
|
||||
if let Err(e) = dotenv::dotenv() {
|
||||
// Display the error if it is something other than the .env file not existing
|
||||
if !e.not_found() {
|
||||
return Err(e).context("could not load .env file");
|
||||
}
|
||||
}
|
||||
|
||||
// Setup logging & tracing
|
||||
let fmt_layer = tracing_subscriber::fmt::layer().with_writer(std::io::stderr);
|
||||
let filter_layer = EnvFilter::try_from_default_env().or_else(|_| EnvFilter::try_new("info"))?;
|
||||
|
||||
let subscriber = Registry::default().with(filter_layer).with(fmt_layer);
|
||||
subscriber
|
||||
.try_init()
|
||||
.context("could not initialize logging")?;
|
||||
|
||||
// Parse the CLI arguments
|
||||
let opts = RootCommand::parse();
|
||||
|
||||
// And run the command
|
||||
opts.run().await
|
||||
}
|
@ -14,10 +14,11 @@
|
||||
|
||||
use argon2::Argon2;
|
||||
use clap::Clap;
|
||||
use mas_config::DatabaseConfig;
|
||||
use mas_core::storage::register_user;
|
||||
use tracing::{info, warn};
|
||||
|
||||
use super::RootCommand;
|
||||
use crate::{config::DatabaseConfig, storage::register_user};
|
||||
|
||||
#[derive(Clap, Debug)]
|
||||
pub(super) struct ManageCommand {
|
@ -20,6 +20,11 @@ use std::{
|
||||
use anyhow::Context;
|
||||
use clap::Clap;
|
||||
use hyper::{header, Server};
|
||||
use mas_config::RootConfig;
|
||||
use mas_core::{
|
||||
tasks::{self, TaskQueue},
|
||||
templates::Templates,
|
||||
};
|
||||
use tower::{make::Shared, ServiceBuilder};
|
||||
use tower_http::{
|
||||
compression::CompressionLayer,
|
||||
@ -29,11 +34,6 @@ use tower_http::{
|
||||
};
|
||||
|
||||
use super::RootCommand;
|
||||
use crate::{
|
||||
config::RootConfig,
|
||||
tasks::{self, TaskQueue},
|
||||
templates::Templates,
|
||||
};
|
||||
|
||||
#[derive(Clap, Debug, Default)]
|
||||
pub(super) struct ServerCommand;
|
||||
@ -52,7 +52,7 @@ impl ServerCommand {
|
||||
let templates = Templates::load().context("could not load templates")?;
|
||||
|
||||
// Start the server
|
||||
let root = crate::handlers::root(&pool, &templates, &config);
|
||||
let root = mas_core::handlers::root(&pool, &templates, &config);
|
||||
|
||||
let queue = TaskQueue::default();
|
||||
queue.recuring(Duration::from_secs(15), tasks::cleanup_expired(&pool));
|
38
crates/config/Cargo.toml
Normal file
38
crates/config/Cargo.toml
Normal file
@ -0,0 +1,38 @@
|
||||
[package]
|
||||
name = "mas-config"
|
||||
version = "0.1.0"
|
||||
authors = ["Quentin Gliech <quenting@element.io>"]
|
||||
edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.11.0", features = [] }
|
||||
tracing = "0.1.27"
|
||||
async-trait = "0.1.51"
|
||||
|
||||
thiserror = "1.0.29"
|
||||
anyhow = "1.0.44"
|
||||
|
||||
schemars = { version = "0.8.3", features = ["url", "chrono"] }
|
||||
figment = { version = "0.10.6", features = ["env", "yaml", "test"] }
|
||||
chrono = { version = "0.4.19", features = ["serde"] }
|
||||
url = { version = "2.2.2", features = ["serde"] }
|
||||
|
||||
serde = { version = "1.0.130", features = ["derive"] }
|
||||
serde_with = { version = "1.10.0", features = ["hex", "chrono"] }
|
||||
serde_json = "1.0.68"
|
||||
sqlx = { version = "0.5.7", features = ["runtime-tokio-rustls", "postgres"] }
|
||||
|
||||
rand = "0.8.4"
|
||||
rsa = "0.5.0"
|
||||
k256 = "0.9.6"
|
||||
pkcs8 = { version = "0.7.6", features = ["pem"] }
|
||||
elliptic-curve = { version = "0.10.6", features = ["pem"] }
|
||||
|
||||
indoc = "1.0.3"
|
||||
|
||||
[dependencies.jwt-compact]
|
||||
# Waiting on the next release because of the bump of the `rsa` dependency
|
||||
git = "https://github.com/slowli/jwt-compact.git"
|
||||
rev = "7a6dee6824c1d4e7c7f81019c9a968e5c9e44923"
|
||||
features = ["rsa", "k256"]
|
@ -42,4 +42,8 @@ impl ConfigurationSection<'_> for CookiesConfig {
|
||||
secret: rand::random(),
|
||||
})
|
||||
}
|
||||
|
||||
fn test() -> Self {
|
||||
Self { secret: [0xEA; 32] }
|
||||
}
|
||||
}
|
@ -52,6 +52,10 @@ impl ConfigurationSection<'_> for CsrfConfig {
|
||||
async fn generate() -> anyhow::Result<Self> {
|
||||
Ok(Self::default())
|
||||
}
|
||||
|
||||
fn test() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
@ -19,12 +19,11 @@ use async_trait::async_trait;
|
||||
use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{serde_as, skip_serializing_none};
|
||||
use sqlx::{
|
||||
postgres::{PgConnectOptions, PgPool, PgPoolOptions},
|
||||
ConnectOptions,
|
||||
};
|
||||
use tracing::log::LevelFilter;
|
||||
use sqlx::postgres::{PgConnectOptions, PgPool, PgPoolOptions};
|
||||
|
||||
// FIXME
|
||||
// use sqlx::ConnectOptions
|
||||
// use tracing::log::LevelFilter;
|
||||
use super::ConfigurationSection;
|
||||
|
||||
fn default_uri() -> String {
|
||||
@ -102,15 +101,16 @@ pub struct DatabaseConfig {
|
||||
impl DatabaseConfig {
|
||||
#[tracing::instrument(err)]
|
||||
pub async fn connect(&self) -> anyhow::Result<PgPool> {
|
||||
let mut options = self
|
||||
let options = self
|
||||
.uri
|
||||
.parse::<PgConnectOptions>()
|
||||
.context("invalid database URL")?
|
||||
.application_name("matrix-authentication-service");
|
||||
|
||||
options
|
||||
.log_statements(LevelFilter::Debug)
|
||||
.log_slow_statements(LevelFilter::Warn, Duration::from_millis(100));
|
||||
// FIXME
|
||||
// options
|
||||
// .log_statements(LevelFilter::Debug)
|
||||
// .log_slow_statements(LevelFilter::Warn, Duration::from_millis(100));
|
||||
|
||||
PgPoolOptions::new()
|
||||
.max_connections(self.max_connections)
|
||||
@ -133,6 +133,10 @@ impl ConfigurationSection<'_> for DatabaseConfig {
|
||||
async fn generate() -> anyhow::Result<Self> {
|
||||
Ok(Self::default())
|
||||
}
|
||||
|
||||
fn test() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
@ -45,4 +45,8 @@ impl ConfigurationSection<'_> for HttpConfig {
|
||||
async fn generate() -> anyhow::Result<Self> {
|
||||
Ok(Self::default())
|
||||
}
|
||||
|
||||
fn test() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
@ -63,4 +63,14 @@ impl ConfigurationSection<'_> for RootConfig {
|
||||
csrf: CsrfConfig::generate().await?,
|
||||
})
|
||||
}
|
||||
|
||||
fn test() -> Self {
|
||||
Self {
|
||||
oauth2: OAuth2Config::test(),
|
||||
http: HttpConfig::test(),
|
||||
database: DatabaseConfig::test(),
|
||||
cookies: CookiesConfig::test(),
|
||||
csrf: CsrfConfig::test(),
|
||||
}
|
||||
}
|
||||
}
|
@ -341,9 +341,49 @@ impl OAuth2Config {
|
||||
.join(".well-known/openid-configuration")
|
||||
.expect("could not build discovery url")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn test() -> Self {
|
||||
#[async_trait]
|
||||
impl ConfigurationSection<'_> for OAuth2Config {
|
||||
fn path() -> &'static str {
|
||||
"oauth2"
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
async fn generate() -> anyhow::Result<Self> {
|
||||
info!("Generating keys...");
|
||||
|
||||
let span = tracing::info_span!("rsa");
|
||||
let rsa_key = task::spawn_blocking(move || {
|
||||
let _entered = span.enter();
|
||||
let mut rng = rand::thread_rng();
|
||||
let ret =
|
||||
RsaPrivateKey::new(&mut rng, 2048).context("could not generate RSA private key");
|
||||
info!("Done generating RSA key");
|
||||
ret
|
||||
})
|
||||
.await
|
||||
.context("could not join blocking task")??;
|
||||
|
||||
let span = tracing::info_span!("ecdsa");
|
||||
let ecdsa_key = task::spawn_blocking(move || {
|
||||
let _entered = span.enter();
|
||||
let rng = rand::thread_rng();
|
||||
let ret = k256::SecretKey::random(rng);
|
||||
info!("Done generating ECDSA key");
|
||||
ret
|
||||
})
|
||||
.await
|
||||
.context("could not join blocking task")?;
|
||||
|
||||
Ok(Self {
|
||||
issuer: default_oauth2_issuer(),
|
||||
clients: Vec::new(),
|
||||
keys: KeySet(vec![Key::from_rsa(rsa_key), Key::from_ecdsa(ecdsa_key)]),
|
||||
})
|
||||
}
|
||||
|
||||
fn test() -> Self {
|
||||
let rsa_key = Key::from_rsa_pem(indoc::indoc! {r#"
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAymS2RkeIZo7pUeEN
|
||||
@ -374,47 +414,6 @@ impl OAuth2Config {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ConfigurationSection<'_> for OAuth2Config {
|
||||
fn path() -> &'static str {
|
||||
"oauth2"
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
async fn generate() -> anyhow::Result<Self> {
|
||||
info!("Generating keys...");
|
||||
|
||||
let span = tracing::info_span!("rsa");
|
||||
let rsa_key = task::spawn_blocking(move || {
|
||||
let _entered = span.enter();
|
||||
let mut rng = rand::thread_rng();
|
||||
let ret =
|
||||
RsaPrivateKey::new(&mut rng, 2048).context("could not generate RSA private key");
|
||||
info!("Done generating RSA key");
|
||||
ret
|
||||
});
|
||||
|
||||
let span = tracing::info_span!("ecdsa");
|
||||
let ecdsa_key = task::spawn_blocking(move || {
|
||||
let _entered = span.enter();
|
||||
let rng = rand::thread_rng();
|
||||
let ret = k256::SecretKey::random(rng);
|
||||
info!("Done generating ECDSA key");
|
||||
ret
|
||||
});
|
||||
|
||||
let (ecdsa_key, rsa_key) = tokio::join!(ecdsa_key, rsa_key);
|
||||
let rsa_key = rsa_key.context("could not join blocking task")??;
|
||||
let ecdsa_key = ecdsa_key.context("could not join blocking task")?;
|
||||
|
||||
Ok(Self {
|
||||
issuer: default_oauth2_issuer(),
|
||||
clients: Vec::new(),
|
||||
keys: KeySet(vec![Key::from_rsa(rsa_key), Key::from_ecdsa(ecdsa_key)]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use figment::Jail;
|
@ -66,4 +66,7 @@ pub trait ConfigurationSection<'a>: Sized + Deserialize<'a> + Serialize {
|
||||
.merge(Yaml::file(path))
|
||||
.extract_inner(Self::path())
|
||||
}
|
||||
|
||||
/// Generate config used in unit tests
|
||||
fn test() -> Self;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "matrix-authentication-service"
|
||||
name = "mas-core"
|
||||
version = "0.1.0"
|
||||
authors = ["Quentin Gliech <quenting@element.io>"]
|
||||
edition = "2018"
|
||||
@ -14,7 +14,6 @@ futures-util = "0.3.17"
|
||||
|
||||
# Logging and tracing
|
||||
tracing = "0.1.27"
|
||||
tracing-subscriber = "0.2.22"
|
||||
|
||||
# Error management
|
||||
thiserror = "1.0.29"
|
||||
@ -22,8 +21,6 @@ anyhow = "1.0.44"
|
||||
|
||||
# Web server
|
||||
warp = "0.3.1"
|
||||
tower = { version = "0.4.8", features = ["full"] }
|
||||
tower-http = { version = "0.1.1", features = ["full"] }
|
||||
hyper = { version = "0.14.12", features = ["full"] }
|
||||
|
||||
# Template engine
|
||||
@ -40,10 +37,8 @@ serde_json = "1.0.68"
|
||||
serde_urlencoded = "0.7.0"
|
||||
|
||||
# Argument & config parsing
|
||||
clap = "3.0.0-beta.4"
|
||||
figment = { version = "0.10.6", features = ["env", "yaml", "test"] }
|
||||
schemars = { version = "0.8.3", features = ["url", "chrono"] }
|
||||
dotenv = "0.15.0"
|
||||
|
||||
# Password hashing
|
||||
argon2 = { version = "0.3.1", features = ["password-hash"] }
|
||||
@ -70,6 +65,7 @@ headers = "0.3.4"
|
||||
cookie = "0.15.1"
|
||||
|
||||
oauth2-types = { path = "../oauth2-types", features = ["sqlx_type"] }
|
||||
mas-config = { path = "../config" }
|
||||
|
||||
[dependencies.jwt-compact]
|
||||
# Waiting on the next release because of the bump of the `rsa` dependency
|
@ -93,7 +93,7 @@ pub struct ErroredForm<FieldType> {
|
||||
}
|
||||
|
||||
impl<T> ErroredForm<T> {
|
||||
pub fn new() -> Self {
|
||||
#[must_use] pub fn new() -> Self {
|
||||
Self {
|
||||
form: Vec::new(),
|
||||
fields: Vec::new(),
|
@ -28,11 +28,13 @@ pub enum ClientAuthentication {
|
||||
}
|
||||
|
||||
impl ClientAuthentication {
|
||||
#[must_use]
|
||||
pub fn public(&self) -> bool {
|
||||
matches!(self, &Self::None)
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_client_auth<T: DeserializeOwned + Send + 'static>(
|
||||
oauth2_config: &OAuth2Config,
|
||||
) -> impl Filter<Extract = (ClientAuthentication, OAuth2ClientConfig, T), Error = Rejection>
|
||||
@ -132,6 +134,8 @@ struct ClientAuthForm<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use mas_config::ConfigurationSection;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn oauth2_config() -> OAuth2Config {
|
@ -69,7 +69,7 @@ impl EncryptedCookie {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn maybe_encrypted<T>(
|
||||
#[must_use] pub fn maybe_encrypted<T>(
|
||||
options: &CookiesConfig,
|
||||
) -> impl Filter<Extract = (Option<T>,), Error = Infallible> + Clone + Send + Sync + 'static
|
||||
where
|
||||
@ -83,7 +83,7 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub fn encrypted<T>(
|
||||
#[must_use] pub fn encrypted<T>(
|
||||
options: &CookiesConfig,
|
||||
) -> impl Filter<Extract = (T,), Error = Rejection> + Clone + Send + Sync + 'static
|
||||
where
|
||||
@ -97,7 +97,7 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub fn with_cookie_saver(
|
||||
#[must_use] pub fn with_cookie_saver(
|
||||
options: &CookiesConfig,
|
||||
) -> impl Filter<Extract = (EncryptedCookieSaver,), Error = Infallible> + Clone + Send + Sync + 'static
|
||||
{
|
@ -66,7 +66,7 @@ impl CsrfToken {
|
||||
}
|
||||
|
||||
/// Get the value to include in HTML forms
|
||||
pub fn form_value(&self) -> String {
|
||||
#[must_use] pub fn form_value(&self) -> String {
|
||||
BASE64URL_NOPAD.encode(&self.token[..])
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ impl<T> CsrfForm<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn csrf_token(
|
||||
#[must_use] pub fn csrf_token(
|
||||
cookies_config: &CookiesConfig,
|
||||
) -> impl Filter<Extract = (CsrfToken,), Error = Rejection> + Clone + Send + Sync + 'static {
|
||||
super::cookies::encrypted(cookies_config).and_then(move |token: CsrfToken| async move {
|
||||
@ -121,7 +121,7 @@ pub fn csrf_token(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn updated_csrf_token(
|
||||
#[must_use] pub fn updated_csrf_token(
|
||||
cookies_config: &CookiesConfig,
|
||||
csrf_config: &CsrfConfig,
|
||||
) -> impl Filter<Extract = (CsrfToken,), Error = Rejection> + Clone + Send + Sync + 'static {
|
||||
@ -144,7 +144,7 @@ pub fn updated_csrf_token(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn protected_form<T>(
|
||||
#[must_use] pub fn protected_form<T>(
|
||||
cookies_config: &CookiesConfig,
|
||||
) -> impl Filter<Extract = (T,), Error = Rejection> + Clone + Send + Sync + 'static
|
||||
where
|
@ -33,14 +33,14 @@ use crate::{
|
||||
templates::Templates,
|
||||
};
|
||||
|
||||
pub fn with_templates(
|
||||
#[must_use] pub fn with_templates(
|
||||
templates: &Templates,
|
||||
) -> impl Filter<Extract = (Templates,), Error = Infallible> + Clone + Send + Sync + 'static {
|
||||
let templates = templates.clone();
|
||||
warp::any().map(move || templates.clone())
|
||||
}
|
||||
|
||||
pub fn with_keys(
|
||||
#[must_use] pub fn with_keys(
|
||||
oauth2_config: &OAuth2Config,
|
||||
) -> impl Filter<Extract = (KeySet,), Error = Infallible> + Clone + Send + Sync + 'static {
|
||||
let keyset = oauth2_config.keys.clone();
|
@ -32,7 +32,7 @@ pub struct SessionCookie {
|
||||
}
|
||||
|
||||
impl SessionCookie {
|
||||
pub fn from_session_info(info: &SessionInfo) -> Self {
|
||||
#[must_use] pub fn from_session_info(info: &SessionInfo) -> Self {
|
||||
Self {
|
||||
current: info.key(),
|
||||
}
|
||||
@ -52,7 +52,7 @@ impl EncryptableCookieValue for SessionCookie {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_optional_session(
|
||||
#[must_use] pub fn with_optional_session(
|
||||
pool: &PgPool,
|
||||
cookies_config: &CookiesConfig,
|
||||
) -> impl Filter<Extract = (Option<SessionInfo>,), Error = Rejection> + Clone + Send + Sync + 'static
|
||||
@ -71,7 +71,7 @@ pub fn with_optional_session(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn with_session(
|
||||
#[must_use] pub fn with_session(
|
||||
pool: &PgPool,
|
||||
cookies_config: &CookiesConfig,
|
||||
) -> impl Filter<Extract = (SessionInfo,), Error = Rejection> + Clone + Send + Sync + 'static {
|
@ -25,7 +25,7 @@ mod views;
|
||||
|
||||
use self::{health::filter as health, oauth2::filter as oauth2, views::filter as views};
|
||||
|
||||
pub fn root(
|
||||
#[must_use] pub fn root(
|
||||
pool: &PgPool,
|
||||
templates: &Templates,
|
||||
config: &RootConfig,
|
31
crates/core/src/lib.rs
Normal file
31
crates/core/src/lib.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::all)]
|
||||
#![warn(clippy::pedantic)]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
#![allow(clippy::missing_panics_doc)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
#![allow(clippy::implicit_hasher)]
|
||||
|
||||
pub(crate) use mas_config as config;
|
||||
|
||||
pub mod errors;
|
||||
pub mod filters;
|
||||
pub mod handlers;
|
||||
pub mod storage;
|
||||
pub mod tasks;
|
||||
pub mod templates;
|
||||
pub mod tokens;
|
@ -67,7 +67,7 @@ pub struct OAuth2AccessTokenLookup {
|
||||
}
|
||||
|
||||
impl OAuth2AccessTokenLookup {
|
||||
pub fn exp(&self) -> DateTime<Utc> {
|
||||
#[must_use] pub fn exp(&self) -> DateTime<Utc> {
|
||||
self.created_at + Duration::seconds(i64::from(self.expires_after))
|
||||
}
|
||||
}
|
@ -103,7 +103,7 @@ impl OAuth2Session {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn max_auth_time(&self) -> Option<DateTime<Utc>> {
|
||||
#[must_use] pub fn max_auth_time(&self) -> Option<DateTime<Utc>> {
|
||||
self.max_age
|
||||
.map(|d| Duration::seconds(i64::from(d)))
|
||||
.map(|d| self.created_at - d)
|
@ -44,7 +44,7 @@ pub struct SessionInfo {
|
||||
}
|
||||
|
||||
impl SessionInfo {
|
||||
pub fn key(&self) -> i64 {
|
||||
#[must_use] pub fn key(&self) -> i64 {
|
||||
self.id
|
||||
}
|
||||
|
@ -38,6 +38,6 @@ impl Task for CleanupExpired {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cleanup_expired(pool: &Pool<Postgres>) -> impl Task + Clone {
|
||||
#[must_use] pub fn cleanup_expired(pool: &Pool<Postgres>) -> impl Task + Clone {
|
||||
CleanupExpired(pool.clone())
|
||||
}
|
@ -212,7 +212,7 @@ pub struct IndexContext {
|
||||
}
|
||||
|
||||
impl IndexContext {
|
||||
pub fn new(discovery_url: Url) -> Self {
|
||||
#[must_use] pub fn new(discovery_url: Url) -> Self {
|
||||
Self { discovery_url }
|
||||
}
|
||||
}
|
||||
@ -230,7 +230,7 @@ pub struct LoginContext {
|
||||
}
|
||||
|
||||
impl LoginContext {
|
||||
pub fn with_form_error(form: ErroredForm<LoginFormField>) -> Self {
|
||||
#[must_use] pub fn with_form_error(form: ErroredForm<LoginFormField>) -> Self {
|
||||
Self { form }
|
||||
}
|
||||
}
|
||||
@ -267,22 +267,22 @@ pub struct ErrorContext {
|
||||
}
|
||||
|
||||
impl ErrorContext {
|
||||
pub fn new() -> Self {
|
||||
#[must_use] pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn with_code(mut self, code: &'static str) -> Self {
|
||||
#[must_use] pub fn with_code(mut self, code: &'static str) -> Self {
|
||||
self.code = Some(code);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_description(mut self, description: String) -> Self {
|
||||
#[must_use] pub fn with_description(mut self, description: String) -> Self {
|
||||
self.description = Some(description);
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn with_details(mut self, details: String) -> Self {
|
||||
#[must_use] pub fn with_details(mut self, details: String) -> Self {
|
||||
self.details = Some(details);
|
||||
self
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
// Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![deny(clippy::all)]
|
||||
#![warn(clippy::pedantic)]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::Clap;
|
||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
|
||||
|
||||
mod cli;
|
||||
mod config;
|
||||
mod errors;
|
||||
mod filters;
|
||||
mod handlers;
|
||||
mod storage;
|
||||
mod tasks;
|
||||
mod templates;
|
||||
mod tokens;
|
||||
|
||||
use self::cli::RootCommand;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
// Load environment variables from .env files
|
||||
if let Err(e) = dotenv::dotenv() {
|
||||
// Display the error if it is something other than the .env file not existing
|
||||
if !e.not_found() {
|
||||
return Err(e).context("could not load .env file");
|
||||
}
|
||||
}
|
||||
|
||||
// Setup logging & tracing
|
||||
let fmt_layer = tracing_subscriber::fmt::layer().with_writer(std::io::stderr);
|
||||
let filter_layer = EnvFilter::try_from_default_env().or_else(|_| EnvFilter::try_new("info"))?;
|
||||
|
||||
let subscriber = Registry::default().with(filter_layer).with(fmt_layer);
|
||||
subscriber
|
||||
.try_init()
|
||||
.context("could not initialize logging")?;
|
||||
|
||||
// Parse the CLI arguments
|
||||
let opts = RootCommand::parse();
|
||||
|
||||
// And run the command
|
||||
opts.run().await
|
||||
}
|
Reference in New Issue
Block a user