mas_config/sections/
policy.rs

1// Copyright 2024, 2025 New Vector Ltd.
2// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5// Please see LICENSE files in the repository root for full details.
6
7use camino::Utf8PathBuf;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10use serde_with::serde_as;
11
12use super::ConfigurationSection;
13
14#[cfg(not(any(feature = "docker", feature = "dist")))]
15fn default_policy_path() -> Utf8PathBuf {
16    "./policies/policy.wasm".into()
17}
18
19#[cfg(feature = "docker")]
20fn default_policy_path() -> Utf8PathBuf {
21    "/usr/local/share/mas-cli/policy.wasm".into()
22}
23
24#[cfg(feature = "dist")]
25fn default_policy_path() -> Utf8PathBuf {
26    "./share/policy.wasm".into()
27}
28
29fn is_default_policy_path(value: &Utf8PathBuf) -> bool {
30    *value == default_policy_path()
31}
32
33fn default_client_registration_entrypoint() -> String {
34    "client_registration/violation".to_owned()
35}
36
37fn is_default_client_registration_entrypoint(value: &String) -> bool {
38    *value == default_client_registration_entrypoint()
39}
40
41fn default_register_entrypoint() -> String {
42    "register/violation".to_owned()
43}
44
45fn is_default_register_entrypoint(value: &String) -> bool {
46    *value == default_register_entrypoint()
47}
48
49fn default_authorization_grant_entrypoint() -> String {
50    "authorization_grant/violation".to_owned()
51}
52
53fn is_default_authorization_grant_entrypoint(value: &String) -> bool {
54    *value == default_authorization_grant_entrypoint()
55}
56
57fn default_password_entrypoint() -> String {
58    "password/violation".to_owned()
59}
60
61fn is_default_password_entrypoint(value: &String) -> bool {
62    *value == default_password_entrypoint()
63}
64
65fn default_compat_login_entrypoint() -> String {
66    "compat_login/violation".to_owned()
67}
68
69fn is_default_compat_login_entrypoint(value: &String) -> bool {
70    *value == default_compat_login_entrypoint()
71}
72
73fn default_email_entrypoint() -> String {
74    "email/violation".to_owned()
75}
76
77fn is_default_email_entrypoint(value: &String) -> bool {
78    *value == default_email_entrypoint()
79}
80
81fn default_data() -> serde_json::Value {
82    serde_json::json!({})
83}
84
85fn is_default_data(value: &serde_json::Value) -> bool {
86    *value == default_data()
87}
88
89/// Application secrets
90#[serde_as]
91#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
92pub struct PolicyConfig {
93    /// Path to the WASM module
94    #[serde(
95        default = "default_policy_path",
96        skip_serializing_if = "is_default_policy_path"
97    )]
98    #[schemars(with = "String")]
99    pub wasm_module: Utf8PathBuf,
100
101    /// Entrypoint to use when evaluating client registrations
102    #[serde(
103        default = "default_client_registration_entrypoint",
104        skip_serializing_if = "is_default_client_registration_entrypoint"
105    )]
106    pub client_registration_entrypoint: String,
107
108    /// Entrypoint to use when evaluating user registrations
109    #[serde(
110        default = "default_register_entrypoint",
111        skip_serializing_if = "is_default_register_entrypoint"
112    )]
113    pub register_entrypoint: String,
114
115    /// Entrypoint to use when evaluating authorization grants
116    #[serde(
117        default = "default_authorization_grant_entrypoint",
118        skip_serializing_if = "is_default_authorization_grant_entrypoint"
119    )]
120    pub authorization_grant_entrypoint: String,
121
122    /// Entrypoint to use when evaluating compatibility logins
123    #[serde(
124        default = "default_compat_login_entrypoint",
125        skip_serializing_if = "is_default_compat_login_entrypoint"
126    )]
127    pub compat_login_entrypoint: String,
128
129    /// Entrypoint to use when changing password
130    #[serde(
131        default = "default_password_entrypoint",
132        skip_serializing_if = "is_default_password_entrypoint"
133    )]
134    pub password_entrypoint: String,
135
136    /// Entrypoint to use when adding an email address
137    #[serde(
138        default = "default_email_entrypoint",
139        skip_serializing_if = "is_default_email_entrypoint"
140    )]
141    pub email_entrypoint: String,
142
143    /// Arbitrary data to pass to the policy
144    #[serde(default = "default_data", skip_serializing_if = "is_default_data")]
145    pub data: serde_json::Value,
146}
147
148impl Default for PolicyConfig {
149    fn default() -> Self {
150        Self {
151            wasm_module: default_policy_path(),
152            client_registration_entrypoint: default_client_registration_entrypoint(),
153            register_entrypoint: default_register_entrypoint(),
154            authorization_grant_entrypoint: default_authorization_grant_entrypoint(),
155            compat_login_entrypoint: default_compat_login_entrypoint(),
156            password_entrypoint: default_password_entrypoint(),
157            email_entrypoint: default_email_entrypoint(),
158            data: default_data(),
159        }
160    }
161}
162
163impl PolicyConfig {
164    /// Returns true if the configuration is the default one
165    pub(crate) fn is_default(&self) -> bool {
166        is_default_policy_path(&self.wasm_module)
167            && is_default_client_registration_entrypoint(&self.client_registration_entrypoint)
168            && is_default_register_entrypoint(&self.register_entrypoint)
169            && is_default_authorization_grant_entrypoint(&self.authorization_grant_entrypoint)
170            && is_default_password_entrypoint(&self.password_entrypoint)
171            && is_default_email_entrypoint(&self.email_entrypoint)
172            && is_default_data(&self.data)
173    }
174}
175
176impl ConfigurationSection for PolicyConfig {
177    const PATH: Option<&'static str> = Some("policy");
178}