Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
131 changes: 131 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,10 @@ features = ["rustc"]
[workspace.dependencies.walkdir]
version = "2.5.0"

[workspace.dependencies.webauthn_rp]
version = "0.3.0"
features = ["bin", "serde_relaxed", "custom", "serializable_server_state"]

# HTTP mock server
[workspace.dependencies.wiremock]
version = "0.6.4"
Expand Down
9 changes: 8 additions & 1 deletion crates/cli/src/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use mas_context::LogContext;
use mas_data_model::{BoxClock, BoxRng, SiteConfig, SystemClock};
use mas_handlers::{
ActivityTracker, BoundActivityTracker, CookieManager, ErrorWrapper, GraphQLSchema, Limiter,
MetadataCache, RequesterFingerprint, passwords::PasswordManager,
MetadataCache, RequesterFingerprint, passwords::PasswordManager, webauthn::Webauthn,
};
use mas_i18n::Translator;
use mas_keystore::{Encrypter, Keystore};
Expand Down Expand Up @@ -47,6 +47,7 @@ pub struct AppState {
pub activity_tracker: ActivityTracker,
pub trusted_proxies: Vec<IpNetwork>,
pub limiter: Limiter,
pub webauthn: Webauthn,
}

impl AppState {
Expand Down Expand Up @@ -214,6 +215,12 @@ impl FromRef<AppState> for Arc<dyn HomeserverConnection> {
}
}

impl FromRef<AppState> for Webauthn {
fn from_ref(input: &AppState) -> Self {
input.webauthn.clone()
}
}

impl FromRequestParts<AppState> for BoxClock {
type Rejection = Infallible;

Expand Down
6 changes: 5 additions & 1 deletion crates/cli/src/commands/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::{
database_pool_from_config, homeserver_connection_from_config,
load_policy_factory_dynamic_data_continuously, mailer_from_config,
password_manager_from_config, policy_factory_from_config, site_config_from_config,
templates_from_config, test_mailer_in_background,
templates_from_config, test_mailer_in_background, webauthn_from_config,
},
};

Expand Down Expand Up @@ -191,6 +191,8 @@ impl Options {

let password_manager = password_manager_from_config(&config.passwords).await?;

let webauthn = webauthn_from_config(&config.http, &config.experimental)?;

// The upstream OIDC metadata cache
let metadata_cache = MetadataCache::new();

Expand Down Expand Up @@ -226,6 +228,7 @@ impl Options {
password_manager.clone(),
url_builder.clone(),
limiter.clone(),
webauthn.clone(),
);

let state = {
Expand All @@ -246,6 +249,7 @@ impl Options {
activity_tracker,
trusted_proxies,
limiter,
webauthn,
};
s.init_metrics();
s.init_metadata_cache();
Expand Down
20 changes: 17 additions & 3 deletions crates/cli/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use std::{sync::Arc, time::Duration};
use anyhow::Context;
use mas_config::{
AccountConfig, BrandingConfig, CaptchaConfig, DatabaseConfig, EmailConfig, EmailSmtpMode,
EmailTransportKind, ExperimentalConfig, HomeserverKind, MatrixConfig, PasswordsConfig,
PolicyConfig, TemplatesConfig,
EmailTransportKind, ExperimentalConfig, HomeserverKind, HttpConfig, MatrixConfig,
PasswordsConfig, PolicyConfig, TemplatesConfig,
};
use mas_context::LogContext;
use mas_data_model::{SessionExpirationConfig, SiteConfig};
use mas_email::{MailTransport, Mailer};
use mas_handlers::passwords::PasswordManager;
use mas_handlers::{passwords::PasswordManager, webauthn::Webauthn};
use mas_matrix::{HomeserverConnection, ReadOnlyHomeserverConnection};
use mas_matrix_synapse::{LegacySynapseConnection, SynapseConnection};
use mas_policy::PolicyFactory;
Expand Down Expand Up @@ -224,6 +224,10 @@ pub fn site_config_from_config(
session_expiration,
login_with_email_allowed: account_config.login_with_email_allowed,
plan_management_iframe_uri: experimental_config.plan_management_iframe_uri.clone(),
passkeys_enabled: experimental_config
.passkeys
.as_ref()
.is_some_and(|c| c.enabled),
})
}

Expand Down Expand Up @@ -496,6 +500,16 @@ pub async fn homeserver_connection_from_config(
})
}

pub fn webauthn_from_config(
http_config: &HttpConfig,
experimental_config: &ExperimentalConfig,
) -> Result<Webauthn, anyhow::Error> {
Webauthn::new(
&http_config.public_base,
experimental_config.passkeys.as_ref(),
)
}

#[cfg(test)]
mod tests {
use rand::SeedableRng;
Expand Down
25 changes: 25 additions & 0 deletions crates/config/src/sections/experimental.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,23 @@ pub struct InactiveSessionExpirationConfig {
pub expire_user_sessions: bool,
}

/// Configuration options for passkeys
#[serde_as]
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)]
pub struct PasskeysConfig {
/// Whether passkeys are enabled or not
#[serde(default)]
pub enabled: bool,
/// Relying Party Identifier to use
///
/// If not set, the host from `public_base` is used
#[serde(default)]
pub rpid: Option<String>,
/// Additional allowed origins. `rpid` and `public_base` are already allowed
#[serde(default)]
pub allowed_origins: Option<Vec<String>>,
}

/// Configuration sections for experimental options
///
/// Do not change these options unless you know what you are doing.
Expand Down Expand Up @@ -81,6 +98,12 @@ pub struct ExperimentalConfig {
/// validation.
#[serde(skip_serializing_if = "Option::is_none")]
pub plan_management_iframe_uri: Option<String>,

/// Experimental passkey support
///
/// Disabled by default
#[serde(skip_serializing_if = "Option::is_none")]
pub passkeys: Option<PasskeysConfig>,
}

impl Default for ExperimentalConfig {
Expand All @@ -90,6 +113,7 @@ impl Default for ExperimentalConfig {
compat_token_ttl: default_token_ttl(),
inactive_session_expiration: None,
plan_management_iframe_uri: None,
passkeys: None,
}
}
}
Expand All @@ -100,6 +124,7 @@ impl ExperimentalConfig {
&& is_default_token_ttl(&self.compat_token_ttl)
&& self.inactive_session_expiration.is_none()
&& self.plan_management_iframe_uri.is_none()
&& self.passkeys.is_none()
}
}

Expand Down
Loading
Loading