mas_handlers/graphql/model/
site_config.rs

1// Copyright 2024 New Vector Ltd.
2// Copyright 2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only
5// Please see LICENSE in the repository root for full details.
6
7#![allow(clippy::str_to_string)] // ComplexObject macro uses &str.to_string()
8
9use async_graphql::{ComplexObject, Enum, ID, SimpleObject};
10use url::Url;
11
12pub const SITE_CONFIG_ID: &str = "site_config";
13pub const CAPTCHA_CONFIG_ID: &str = "captcha_config";
14
15#[derive(SimpleObject)]
16#[graphql(complex)]
17#[allow(clippy::struct_excessive_bools)]
18pub struct SiteConfig {
19    /// The configuration of CAPTCHA provider.
20    captcha_config: Option<CaptchaConfig>,
21
22    /// The server name of the homeserver.
23    server_name: String,
24
25    /// The URL to the privacy policy.
26    policy_uri: Option<Url>,
27
28    /// The URL to the terms of service.
29    tos_uri: Option<Url>,
30
31    /// Imprint to show in the footer.
32    imprint: Option<String>,
33
34    /// Whether users can change their email.
35    email_change_allowed: bool,
36
37    /// Whether users can change their display name.
38    display_name_change_allowed: bool,
39
40    /// Whether passwords are enabled for login.
41    password_login_enabled: bool,
42
43    /// Whether passwords are enabled and users can change their own passwords.
44    password_change_allowed: bool,
45
46    /// Whether passwords are enabled and users can register using a password.
47    password_registration_enabled: bool,
48
49    /// Whether users can delete their own account.
50    account_deactivation_allowed: bool,
51
52    /// Minimum password complexity, from 0 to 4, in terms of a zxcvbn score.
53    /// The exact scorer (including dictionaries and other data tables)
54    /// in use is <https://crates.io/crates/zxcvbn>.
55    minimum_password_complexity: u8,
56
57    /// Whether users can log in with their email address.
58    login_with_email_allowed: bool,
59
60    /// Experimental plan management iframe URI.
61    plan_management_iframe_uri: Option<String>,
62}
63
64#[derive(SimpleObject)]
65#[graphql(complex)]
66pub struct CaptchaConfig {
67    /// Which Captcha service is being used
68    pub service: CaptchaService,
69
70    /// The site key used by the instance
71    pub site_key: String,
72}
73
74/// Which Captcha service is being used
75#[derive(Enum, Debug, Clone, Copy, PartialEq, Eq)]
76pub enum CaptchaService {
77    RecaptchaV2,
78    CloudflareTurnstile,
79    HCaptcha,
80}
81
82#[ComplexObject]
83impl SiteConfig {
84    /// The ID of the site configuration.
85    pub async fn id(&self) -> ID {
86        SITE_CONFIG_ID.into()
87    }
88}
89
90impl SiteConfig {
91    /// Create a new [`SiteConfig`] from the data model
92    /// [`mas_data_model:::SiteConfig`].
93    pub fn new(data_model: &mas_data_model::SiteConfig) -> Self {
94        Self {
95            captcha_config: data_model.captcha.as_ref().map(CaptchaConfig::new),
96            server_name: data_model.server_name.clone(),
97            policy_uri: data_model.policy_uri.clone(),
98            tos_uri: data_model.tos_uri.clone(),
99            imprint: data_model.imprint.clone(),
100            email_change_allowed: data_model.email_change_allowed,
101            display_name_change_allowed: data_model.displayname_change_allowed,
102            password_login_enabled: data_model.password_login_enabled,
103            password_change_allowed: data_model.password_change_allowed,
104            password_registration_enabled: data_model.password_registration_enabled,
105            account_deactivation_allowed: data_model.account_deactivation_allowed,
106            minimum_password_complexity: data_model.minimum_password_complexity,
107            login_with_email_allowed: data_model.login_with_email_allowed,
108            plan_management_iframe_uri: data_model.plan_management_iframe_uri.clone(),
109        }
110    }
111}
112
113#[ComplexObject]
114impl CaptchaConfig {
115    pub async fn id(&self) -> ID {
116        CAPTCHA_CONFIG_ID.into()
117    }
118}
119
120impl CaptchaConfig {
121    /// Create a new [`CaptchaConfig`] from the data model
122    /// [`mas_data_model:::CaptchaConfig`].
123    pub fn new(data_model: &mas_data_model::CaptchaConfig) -> Self {
124        Self {
125            service: match data_model.service {
126                mas_data_model::CaptchaService::RecaptchaV2 => CaptchaService::RecaptchaV2,
127                mas_data_model::CaptchaService::CloudflareTurnstile => {
128                    CaptchaService::CloudflareTurnstile
129                }
130                mas_data_model::CaptchaService::HCaptcha => CaptchaService::HCaptcha,
131            },
132            site_key: data_model.site_key.clone(),
133        }
134    }
135}