Skip to content

Commit 1f0377f

Browse files
committed
add tchap configuration
1 parent 80ef509 commit 1f0377f

File tree

14 files changed

+279
-52
lines changed

14 files changed

+279
-52
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cli/src/app_state.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::{convert::Infallible, net::IpAddr, sync::Arc};
99
use axum::extract::{FromRef, FromRequestParts};
1010
use ipnetwork::IpNetwork;
1111
use mas_context::LogContext;
12-
use mas_data_model::SiteConfig;
12+
use mas_data_model::{SiteConfig, TchapConfig};
1313
use mas_handlers::{
1414
ActivityTracker, BoundActivityTracker, CookieManager, ErrorWrapper, GraphQLSchema, Limiter,
1515
MetadataCache, RequesterFingerprint, passwords::PasswordManager,
@@ -49,6 +49,7 @@ pub struct AppState {
4949
pub activity_tracker: ActivityTracker,
5050
pub trusted_proxies: Vec<IpNetwork>,
5151
pub limiter: Limiter,
52+
pub tchap_config: TchapConfig,
5253
}
5354

5455
impl AppState {
@@ -216,6 +217,12 @@ impl FromRef<AppState> for Arc<dyn HomeserverConnection> {
216217
}
217218
}
218219

220+
impl FromRef<AppState> for TchapConfig {
221+
fn from_ref(input: &AppState) -> Self {
222+
input.tchap_config.clone()
223+
}
224+
}
225+
219226
impl FromRequestParts<AppState> for BoxClock {
220227
type Rejection = Infallible;
221228

crates/cli/src/commands/server.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ use clap::Parser;
1111
use figment::Figment;
1212
use itertools::Itertools;
1313
use mas_config::{
14-
AppConfig, ClientsConfig, ConfigurationSection, ConfigurationSectionExt, UpstreamOAuth2Config,
14+
AppConfig, ClientsConfig, ConfigurationSection, ConfigurationSectionExt, TchapAppConfig,
15+
UpstreamOAuth2Config,
1516
};
1617
use mas_context::LogContext;
18+
use mas_data_model::TchapConfig;
1719
use mas_handlers::{ActivityTracker, CookieManager, Limiter, MetadataCache};
1820
use mas_listener::server::Server;
1921
use mas_router::UrlBuilder;
@@ -59,6 +61,8 @@ impl Options {
5961
let span = info_span!("cli.run.init").entered();
6062
let mut shutdown = LifecycleManager::new()?;
6163
let config = AppConfig::extract(figment).map_err(anyhow::Error::from_boxed)?;
64+
let tchap_app_config =
65+
TchapAppConfig::extract(figment).map_err(anyhow::Error::from_boxed)?;
6266

6367
info!(version = crate::VERSION, "Starting up");
6468

@@ -159,6 +163,8 @@ impl Options {
159163
&config.captcha,
160164
)?;
161165

166+
let tchap_config = tchap_config_from_tchap_app_config(&tchap_app_config);
167+
162168
// Load and compile the templates
163169
let templates =
164170
templates_from_config(&config.templates, &site_config, &url_builder).await?;
@@ -246,6 +252,7 @@ impl Options {
246252
activity_tracker,
247253
trusted_proxies,
248254
limiter,
255+
tchap_config,
249256
};
250257
s.init_metrics();
251258
s.init_metadata_cache();
@@ -334,3 +341,9 @@ impl Options {
334341
Ok(exit_code)
335342
}
336343
}
344+
345+
fn tchap_config_from_tchap_app_config(tchap_app_config: &TchapAppConfig) -> TchapConfig {
346+
TchapConfig {
347+
identity_server_url: tchap_app_config.identity_server_url.clone(),
348+
}
349+
}

crates/config/src/sections/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ mod passwords;
2121
mod policy;
2222
mod rate_limiting;
2323
mod secrets;
24+
mod tchap;
2425
mod telemetry;
2526
mod templates;
2627
mod upstream_oauth2;
@@ -44,6 +45,7 @@ pub use self::{
4445
policy::PolicyConfig,
4546
rate_limiting::RateLimitingConfig,
4647
secrets::SecretsConfig,
48+
tchap::TchapAppConfig,
4749
telemetry::{
4850
MetricsConfig, MetricsExporterKind, Propagator, TelemetryConfig, TracingConfig,
4951
TracingExporterKind,
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//
2+
// MIT License
3+
//
4+
// Copyright (c) 2025, Direction interministérielle du numérique - Gouvernement
5+
// Français
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy
8+
// of this software and associated documentation files (the "Software"), to
9+
// deal in the Software without restriction, including without limitation the
10+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11+
// sell copies of the Software, and to permit persons to whom the Software is
12+
// furnished to do so, subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in
15+
// all copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20+
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
24+
//
25+
26+
use schemars::JsonSchema;
27+
use serde::{Deserialize, Serialize};
28+
use serde_with::serde_as;
29+
use url::Url;
30+
31+
use super::ConfigurationSection;
32+
33+
fn default_identity_server_url() -> Url {
34+
Url::parse("http://localhost:8090/").unwrap()
35+
}
36+
37+
/// Tchap specific configuration
38+
#[serde_as]
39+
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
40+
pub struct TchapAppConfig {
41+
/// Identity Server Url
42+
#[serde(default = "default_identity_server_url")]
43+
pub identity_server_url: Url,
44+
}
45+
46+
impl ConfigurationSection for TchapAppConfig {
47+
const PATH: Option<&'static str> = Some("tchap");
48+
49+
// NOTE: implement this function to perform validation on config
50+
fn validate(
51+
&self,
52+
_figment: &figment::Figment,
53+
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
54+
Ok(())
55+
}
56+
}
57+
58+
#[cfg(test)]
59+
mod tests {
60+
use figment::{
61+
Figment, Jail,
62+
providers::{Format, Yaml},
63+
};
64+
65+
use super::*;
66+
67+
#[test]
68+
fn load_config() {
69+
Jail::expect_with(|jail| {
70+
jail.create_file(
71+
"config.yaml",
72+
r"
73+
tchap:
74+
identity_server_url: http://localhost:8091
75+
",
76+
)?;
77+
78+
let config = Figment::new()
79+
.merge(Yaml::file("config.yaml"))
80+
.extract_inner::<TchapAppConfig>("tchap")?;
81+
82+
assert_eq!(
83+
&config.identity_server_url.as_str().to_owned(),
84+
"http://localhost:8091/"
85+
);
86+
87+
Ok(())
88+
});
89+
}
90+
}

crates/data-model/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub(crate) mod compat;
1212
pub mod oauth2;
1313
pub(crate) mod policy_data;
1414
mod site_config;
15+
pub(crate) mod tchap_config;
1516
pub(crate) mod tokens;
1617
pub(crate) mod upstream_oauth2;
1718
pub(crate) mod user_agent;
@@ -35,6 +36,7 @@ pub use self::{
3536
},
3637
policy_data::PolicyData,
3738
site_config::{CaptchaConfig, CaptchaService, SessionExpirationConfig, SiteConfig},
39+
tchap_config::*,
3840
tokens::{
3941
AccessToken, AccessTokenState, RefreshToken, RefreshTokenState, TokenFormatError, TokenType,
4042
},
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// MIT License
3+
//
4+
// Copyright (c) 2025, Direction interministérielle du numérique - Gouvernement
5+
// Français
6+
//
7+
// Permission is hereby granted, free of charge, to any person obtaining a copy
8+
// of this software and associated documentation files (the "Software"), to
9+
// deal in the Software without restriction, including without limitation the
10+
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11+
// sell copies of the Software, and to permit persons to whom the Software is
12+
// furnished to do so, subject to the following conditions:
13+
//
14+
// The above copyright notice and this permission notice shall be included in
15+
// all copies or substantial portions of the Software.
16+
//
17+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19+
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20+
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21+
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
23+
// USE OR OTHER DEALINGS IN THE SOFTWARE.
24+
//
25+
26+
use url::Url;
27+
28+
/// Random tchap configuration we want accessible in various places.
29+
#[allow(clippy::struct_excessive_bools)]
30+
#[derive(Debug, Clone)]
31+
pub struct TchapConfig {
32+
/// Identity Server Url
33+
pub identity_server_url: Url,
34+
}

crates/handlers/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use hyper::{
3636
},
3737
};
3838
use mas_axum_utils::{InternalError, cookies::CookieJar};
39-
use mas_data_model::SiteConfig;
39+
use mas_data_model::{SiteConfig, TchapConfig};
4040
use mas_http::CorsLayerExt;
4141
use mas_keystore::{Encrypter, Keystore};
4242
use mas_matrix::HomeserverConnection;
@@ -349,6 +349,7 @@ where
349349
BoxClock: FromRequestParts<S>,
350350
BoxRng: FromRequestParts<S>,
351351
Policy: FromRequestParts<S>,
352+
TchapConfig: FromRef<S>,
352353
{
353354
Router::new()
354355
// XXX: hard-coded redirect from /account to /account/

crates/handlers/src/test_utils.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use mas_axum_utils::{
2828
cookies::{CookieJar, CookieManager},
2929
};
3030
use mas_config::RateLimitingConfig;
31-
use mas_data_model::SiteConfig;
31+
use mas_data_model::{SiteConfig, TchapConfig};
3232
use mas_email::{MailTransport, Mailer};
3333
use mas_i18n::Translator;
3434
use mas_keystore::{Encrypter, JsonWebKey, JsonWebKeySet, Keystore, PrivateKey};
@@ -115,6 +115,7 @@ pub(crate) struct TestState {
115115
pub rng: Arc<Mutex<ChaChaRng>>,
116116
pub http_client: reqwest::Client,
117117
pub task_tracker: TaskTracker,
118+
pub tchap_config: TchapConfig,
118119
queue_worker: Arc<tokio::sync::Mutex<QueueWorker>>,
119120

120121
#[allow(dead_code)] // It is used, as it will cancel the CancellationToken when dropped
@@ -259,6 +260,8 @@ impl TestState {
259260

260261
let queue_worker = Arc::new(tokio::sync::Mutex::new(queue_worker));
261262

263+
let tchap_config = tchap::test_tchap_config();
264+
262265
Ok(Self {
263266
repository_factory: PgRepositoryFactory::new(pool),
264267
templates,
@@ -280,6 +283,7 @@ impl TestState {
280283
task_tracker,
281284
queue_worker,
282285
cancellation_drop_guard: Arc::new(shutdown_token.drop_guard()),
286+
tchap_config,
283287
})
284288
}
285289

@@ -578,6 +582,12 @@ impl FromRef<TestState> for reqwest::Client {
578582
}
579583
}
580584

585+
impl FromRef<TestState> for TchapConfig {
586+
fn from_ref(input: &TestState) -> Self {
587+
input.tchap_config.clone()
588+
}
589+
}
590+
581591
impl FromRequestParts<TestState> for ActivityTracker {
582592
type Rejection = Infallible;
583593

crates/handlers/src/upstream_oauth2/link.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use mas_axum_utils::{
1919
csrf::{CsrfExt, ProtectedForm},
2020
record_error,
2121
};
22-
use mas_data_model::UpstreamOAuthProviderOnConflict;
22+
use mas_data_model::{TchapConfig, UpstreamOAuthProviderOnConflict};
2323
use mas_jose::jwt::Jwt;
2424
use mas_matrix::HomeserverConnection;
2525
use mas_policy::Policy;
@@ -231,6 +231,7 @@ pub(crate) async fn get(
231231
State(templates): State<Templates>,
232232
State(url_builder): State<UrlBuilder>,
233233
State(homeserver): State<Arc<dyn HomeserverConnection>>,
234+
State(tchap_config): State<TchapConfig>,
234235
cookie_jar: CookieJar,
235236
activity_tracker: BoundActivityTracker,
236237
user_agent: Option<TypedHeader<headers::UserAgent>>,
@@ -450,7 +451,8 @@ pub(crate) async fn get(
450451
Some(value) => {
451452
//:tchap:
452453
let server_name = homeserver.homeserver();
453-
let email_result = check_email_allowed(&value, server_name).await;
454+
let email_result =
455+
check_email_allowed(&value, server_name, &tchap_config).await;
454456

455457
match email_result {
456458
EmailAllowedResult::Allowed => {
@@ -1052,12 +1054,20 @@ pub(crate) async fn post(
10521054
//:tchap:
10531055
///real function used when not testing
10541056
#[cfg(not(test))]
1055-
async fn check_email_allowed(email: &str, server_name: &str) -> EmailAllowedResult {
1056-
tchap::is_email_allowed(email, server_name).await
1057+
async fn check_email_allowed(
1058+
email: &str,
1059+
server_name: &str,
1060+
tchap_config: &TchapConfig,
1061+
) -> EmailAllowedResult {
1062+
tchap::is_email_allowed(email, server_name, tchap_config).await
10571063
}
10581064
///mock function used when testing
10591065
#[cfg(test)]
1060-
async fn check_email_allowed(_email: &str, _server_name: &str) -> EmailAllowedResult {
1066+
async fn check_email_allowed(
1067+
_email: &str,
1068+
_server_name: &str,
1069+
_tchap_config: &TchapConfig,
1070+
) -> EmailAllowedResult {
10611071
EmailAllowedResult::Allowed
10621072
}
10631073
//:tchap:end

0 commit comments

Comments
 (0)