Skip to content
Merged
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
8 changes: 7 additions & 1 deletion crates/handlers/src/admin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use axum::{
use hyper::header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE};
use indexmap::IndexMap;
use mas_axum_utils::InternalError;
use mas_data_model::BoxRng;
use mas_data_model::{BoxRng, SiteConfig};
use mas_http::CorsLayerExt;
use mas_matrix::HomeserverConnection;
use mas_policy::PolicyFactory;
Expand All @@ -43,6 +43,11 @@ use crate::passwords::PasswordManager;

fn finish(t: TransformOpenApi) -> TransformOpenApi {
t.title("Matrix Authentication Service admin API")
.tag(Tag {
name: "server".to_owned(),
description: Some("Information about the server".to_owned()),
..Tag::default()
})
.tag(Tag {
name: "compat-session".to_owned(),
description: Some("Manage compatibility sessions from legacy clients".to_owned()),
Expand Down Expand Up @@ -153,6 +158,7 @@ where
Templates: FromRef<S>,
UrlBuilder: FromRef<S>,
Arc<PolicyFactory>: FromRef<S>,
SiteConfig: FromRef<S>,
{
// We *always* want to explicitly set the possible responses, beacuse the
// infered ones are not necessarily correct
Expand Down
8 changes: 7 additions & 1 deletion crates/handlers/src/admin/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use aide::axum::{
routing::{get_with, post_with},
};
use axum::extract::{FromRef, FromRequestParts};
use mas_data_model::BoxRng;
use mas_data_model::{BoxRng, SiteConfig};
use mas_matrix::HomeserverConnection;
use mas_policy::PolicyFactory;

Expand All @@ -21,6 +21,7 @@ use crate::passwords::PasswordManager;
mod compat_sessions;
mod oauth2_sessions;
mod policy_data;
mod site_config;
mod upstream_oauth_links;
mod user_emails;
mod user_registration_tokens;
Expand All @@ -32,11 +33,16 @@ where
S: Clone + Send + Sync + 'static,
Arc<dyn HomeserverConnection>: FromRef<S>,
PasswordManager: FromRef<S>,
SiteConfig: FromRef<S>,
Arc<PolicyFactory>: FromRef<S>,
BoxRng: FromRequestParts<S>,
CallContext: FromRequestParts<S>,
{
ApiRouter::<S>::new()
.api_route(
"/site-config",
get_with(self::site_config::handler, self::site_config::doc),
)
.api_route(
"/compat-sessions",
get_with(self::compat_sessions::list, self::compat_sessions::list_doc),
Expand Down
92 changes: 92 additions & 0 deletions crates/handlers/src/admin/v1/site_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.

use aide::transform::TransformOperation;
use axum::{Json, extract::State};
use schemars::JsonSchema;
use serde::Serialize;

use crate::admin::call_context::CallContext;

#[allow(clippy::struct_excessive_bools)]
#[derive(Serialize, JsonSchema)]
pub struct SiteConfig {
/// The Matrix server name for which this instance is configured
server_name: String,

/// Whether password login is enabled.
pub password_login_enabled: bool,

/// Whether password registration is enabled.
pub password_registration_enabled: bool,

/// Whether registration tokens are required for password registrations.
pub registration_token_required: bool,

/// Whether users can change their email.
pub email_change_allowed: bool,

/// Whether users can change their display name.
pub displayname_change_allowed: bool,

/// Whether users can change their password.
pub password_change_allowed: bool,

/// Whether users can recover their account via email.
pub account_recovery_allowed: bool,

/// Whether users can delete their own account.
pub account_deactivation_allowed: bool,

/// Whether CAPTCHA during registration is enabled.
pub captcha_enabled: bool,

/// Minimum password complexity, between 0 and 4.
/// This is a score from zxcvbn.
#[schemars(range(min = 0, max = 4))]
pub minimum_password_complexity: u8,
}

pub fn doc(operation: TransformOperation) -> TransformOperation {
operation
.id("siteConfig")
.tag("server")
.summary("Get informations about the configuration of this MAS instance")
.response_with::<200, Json<SiteConfig>, _>(|t| {
t.example(SiteConfig {
server_name: "example.com".to_owned(),
password_login_enabled: true,
password_registration_enabled: true,
registration_token_required: true,
email_change_allowed: true,
displayname_change_allowed: true,
password_change_allowed: true,
account_recovery_allowed: true,
account_deactivation_allowed: true,
captcha_enabled: true,
minimum_password_complexity: 3,
})
})
}

#[tracing::instrument(name = "handler.admin.v1.site_config", skip_all)]
pub async fn handler(
_: CallContext,
State(site_config): State<mas_data_model::SiteConfig>,
) -> Json<SiteConfig> {
Json(SiteConfig {
server_name: site_config.server_name,
password_login_enabled: site_config.password_login_enabled,
password_registration_enabled: site_config.password_registration_enabled,
registration_token_required: site_config.registration_token_required,
email_change_allowed: site_config.email_change_allowed,
displayname_change_allowed: site_config.displayname_change_allowed,
password_change_allowed: site_config.password_change_allowed,
account_recovery_allowed: site_config.account_recovery_allowed,
account_deactivation_allowed: site_config.account_deactivation_allowed,
captcha_enabled: site_config.captcha.is_some(),
minimum_password_complexity: site_config.minimum_password_complexity,
})
}
1 change: 1 addition & 0 deletions crates/handlers/src/bin/api-schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl_from_ref!(Arc<dyn mas_matrix::HomeserverConnection>);
impl_from_ref!(mas_keystore::Keystore);
impl_from_ref!(mas_handlers::passwords::PasswordManager);
impl_from_ref!(Arc<mas_policy::PolicyFactory>);
impl_from_ref!(mas_data_model::SiteConfig);

fn main() -> Result<(), Box<dyn std::error::Error>> {
let (mut api, _) = mas_handlers::admin_api_router::<DummyState>();
Expand Down
103 changes: 103 additions & 0 deletions docs/api/spec.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,40 @@
}
],
"paths": {
"/api/admin/v1/site-config": {
"get": {
"tags": [
"server"
],
"summary": "Get informations about the configuration of this MAS instance",
"operationId": "siteConfig",
"responses": {
"200": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/SiteConfig"
},
"example": {
"server_name": "example.com",
"password_login_enabled": true,
"password_registration_enabled": true,
"registration_token_required": true,
"email_change_allowed": true,
"displayname_change_allowed": true,
"password_change_allowed": true,
"account_recovery_allowed": true,
"account_deactivation_allowed": true,
"captcha_enabled": true,
"minimum_password_complexity": 3
}
}
}
}
}
}
},
"/api/admin/v1/compat-sessions": {
"get": {
"tags": [
Expand Down Expand Up @@ -3186,6 +3220,71 @@
}
},
"schemas": {
"SiteConfig": {
"type": "object",
"required": [
"account_deactivation_allowed",
"account_recovery_allowed",
"captcha_enabled",
"displayname_change_allowed",
"email_change_allowed",
"minimum_password_complexity",
"password_change_allowed",
"password_login_enabled",
"password_registration_enabled",
"registration_token_required",
"server_name"
],
"properties": {
"server_name": {
"description": "The Matrix server name for which this instance is configured",
"type": "string"
},
"password_login_enabled": {
"description": "Whether password login is enabled.",
"type": "boolean"
},
"password_registration_enabled": {
"description": "Whether password registration is enabled.",
"type": "boolean"
},
"registration_token_required": {
"description": "Whether registration tokens are required for password registrations.",
"type": "boolean"
},
"email_change_allowed": {
"description": "Whether users can change their email.",
"type": "boolean"
},
"displayname_change_allowed": {
"description": "Whether users can change their display name.",
"type": "boolean"
},
"password_change_allowed": {
"description": "Whether users can change their password.",
"type": "boolean"
},
"account_recovery_allowed": {
"description": "Whether users can recover their account via email.",
"type": "boolean"
},
"account_deactivation_allowed": {
"description": "Whether users can delete their own account.",
"type": "boolean"
},
"captcha_enabled": {
"description": "Whether CAPTCHA during registration is enabled.",
"type": "boolean"
},
"minimum_password_complexity": {
"description": "Minimum password complexity, between 0 and 4. This is a score from zxcvbn.",
"type": "integer",
"format": "uint8",
"maximum": 4.0,
"minimum": 0.0
}
}
},
"PaginationParams": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -4586,6 +4685,10 @@
}
],
"tags": [
{
"name": "server",
"description": "Information about the server"
},
{
"name": "compat-session",
"description": "Manage compatibility sessions from legacy clients"
Expand Down
Loading