Skip to main content

shared/settings/
ratelimits.rs

1use super::{
2    ExtensionSettings, SettingsDeserializeExt, SettingsDeserializer, SettingsSerializeExt,
3    SettingsSerializer,
4};
5use garde::Validate;
6use serde::{Deserialize, Serialize};
7use utoipa::ToSchema;
8
9#[derive(Clone, Copy, Validate, ToSchema, Serialize, Deserialize)]
10pub struct RatelimitConfiguration {
11    #[garde(range(min = 1))]
12    pub hits: u64,
13    #[garde(range(min = 1))]
14    pub window_seconds: u64,
15}
16
17#[derive(Clone, ToSchema, Serialize, Deserialize)]
18pub struct AppSettingsRatelimits {
19    pub auth_register: RatelimitConfiguration,
20    pub auth_login: RatelimitConfiguration,
21    pub auth_login_checkpoint: RatelimitConfiguration,
22    pub auth_login_checkpoint_email: RatelimitConfiguration,
23    pub auth_login_security_key: RatelimitConfiguration,
24    pub auth_password_forgot: RatelimitConfiguration,
25    pub auth_password_reset: RatelimitConfiguration,
26    pub auth_email_verification: RatelimitConfiguration,
27
28    pub client: RatelimitConfiguration,
29    pub client_account_email_resend_verification: RatelimitConfiguration,
30    pub client_servers_backups_create: RatelimitConfiguration,
31    pub client_servers_files_pull: RatelimitConfiguration,
32    pub client_servers_files_pull_query: RatelimitConfiguration,
33
34    pub remote: RatelimitConfiguration,
35    pub remote_sftp_auth: RatelimitConfiguration,
36    pub remote_enroll: RatelimitConfiguration,
37
38    #[schema(value_type = Vec<String>)]
39    pub exempt_ips: Vec<sqlx::types::ipnetwork::IpNetwork>,
40    pub exempt_api_keys: Vec<uuid::Uuid>,
41}
42
43impl AppSettingsRatelimits {
44    pub fn is_ip_exempt(&self, ip: std::net::IpAddr) -> bool {
45        self.exempt_ips.iter().any(|network| network.contains(ip))
46    }
47
48    pub fn is_api_key_exempt(&self, api_key_uuid: uuid::Uuid) -> bool {
49        self.exempt_api_keys.contains(&api_key_uuid)
50    }
51}
52
53#[async_trait::async_trait]
54impl SettingsSerializeExt for AppSettingsRatelimits {
55    async fn serialize(
56        &self,
57        serializer: SettingsSerializer,
58    ) -> Result<SettingsSerializer, anyhow::Error> {
59        Ok(serializer
60            .write_serde_setting("auth_register", &self.auth_register)?
61            .write_serde_setting("auth_login", &self.auth_login)?
62            .write_serde_setting("auth_login_checkpoint", &self.auth_login_checkpoint)?
63            .write_serde_setting(
64                "auth_login_checkpoint_email",
65                &self.auth_login_checkpoint_email,
66            )?
67            .write_serde_setting("auth_login_security_key", &self.auth_login_security_key)?
68            .write_serde_setting("auth_password_forgot", &self.auth_password_forgot)?
69            .write_serde_setting("auth_password_reset", &self.auth_password_reset)?
70            .write_serde_setting("auth_email_verification", &self.auth_email_verification)?
71            .write_serde_setting("client", &self.client)?
72            .write_serde_setting(
73                "client_account_email_resend_verification",
74                &self.client_account_email_resend_verification,
75            )?
76            .write_serde_setting(
77                "client_servers_backups_create",
78                &self.client_servers_backups_create,
79            )?
80            .write_serde_setting("client_servers_files_pull", &self.client_servers_files_pull)?
81            .write_serde_setting(
82                "client_servers_files_pull_query",
83                &self.client_servers_files_pull_query,
84            )?
85            .write_serde_setting("remote", &self.remote)?
86            .write_serde_setting("remote_sftp_auth", &self.remote_sftp_auth)?
87            .write_serde_setting("remote_enroll", &self.remote_enroll)?
88            .write_serde_setting("exempt_ips", &self.exempt_ips)?
89            .write_serde_setting("exempt_api_keys", &self.exempt_api_keys)?)
90    }
91}
92
93pub struct AppSettingsRatelimitsDeserializer;
94
95#[async_trait::async_trait]
96impl SettingsDeserializeExt for AppSettingsRatelimitsDeserializer {
97    async fn deserialize_boxed(
98        &self,
99        deserializer: SettingsDeserializer<'_>,
100    ) -> Result<ExtensionSettings, anyhow::Error> {
101        Ok(Box::new(AppSettingsRatelimits {
102            auth_register: deserializer.read_serde_setting("auth_register").unwrap_or(
103                RatelimitConfiguration {
104                    hits: 10,
105                    window_seconds: 3600,
106                },
107            ),
108            auth_login: deserializer.read_serde_setting("auth_login").unwrap_or(
109                RatelimitConfiguration {
110                    hits: 20,
111                    window_seconds: 300,
112                },
113            ),
114            auth_login_checkpoint: deserializer
115                .read_serde_setting("auth_login_checkpoint")
116                .unwrap_or(RatelimitConfiguration {
117                    hits: 10,
118                    window_seconds: 300,
119                }),
120            auth_login_checkpoint_email: deserializer
121                .read_serde_setting("auth_login_checkpoint_email")
122                .unwrap_or(RatelimitConfiguration {
123                    hits: 5,
124                    window_seconds: 900,
125                }),
126            auth_login_security_key: deserializer
127                .read_serde_setting("auth_login_security_key")
128                .unwrap_or(RatelimitConfiguration {
129                    hits: 10,
130                    window_seconds: 300,
131                }),
132            auth_password_forgot: deserializer
133                .read_serde_setting("auth_password_forgot")
134                .unwrap_or(RatelimitConfiguration {
135                    hits: 10,
136                    window_seconds: 3600,
137                }),
138            auth_password_reset: deserializer
139                .read_serde_setting("auth_password_reset")
140                .unwrap_or(RatelimitConfiguration {
141                    hits: 10,
142                    window_seconds: 300,
143                }),
144            auth_email_verification: deserializer
145                .read_serde_setting("auth_email_verification")
146                .unwrap_or(RatelimitConfiguration {
147                    hits: 10,
148                    window_seconds: 3600,
149                }),
150            client: deserializer
151                .read_serde_setting("client")
152                .unwrap_or(RatelimitConfiguration {
153                    hits: 360,
154                    window_seconds: 30,
155                }),
156            client_account_email_resend_verification: deserializer
157                .read_serde_setting("client_account_email_resend_verification")
158                .unwrap_or(RatelimitConfiguration {
159                    hits: 10,
160                    window_seconds: 3600,
161                }),
162            client_servers_backups_create: deserializer
163                .read_serde_setting("client_servers_backups_create")
164                .unwrap_or(RatelimitConfiguration {
165                    hits: 4,
166                    window_seconds: 300,
167                }),
168            client_servers_files_pull: deserializer
169                .read_serde_setting("client_servers_files_pull")
170                .unwrap_or(RatelimitConfiguration {
171                    hits: 5,
172                    window_seconds: 60,
173                }),
174            client_servers_files_pull_query: deserializer
175                .read_serde_setting("client_servers_files_pull_query")
176                .unwrap_or(RatelimitConfiguration {
177                    hits: 10,
178                    window_seconds: 60,
179                }),
180            remote: deserializer
181                .read_serde_setting("remote")
182                .unwrap_or(RatelimitConfiguration {
183                    hits: 720,
184                    window_seconds: 30,
185                }),
186            remote_sftp_auth: deserializer
187                .read_serde_setting("remote_sftp_auth")
188                .unwrap_or(RatelimitConfiguration {
189                    hits: 60,
190                    window_seconds: 30,
191                }),
192            remote_enroll: deserializer.read_serde_setting("remote_enroll").unwrap_or(
193                RatelimitConfiguration {
194                    hits: 10,
195                    window_seconds: 60,
196                },
197            ),
198            exempt_ips: deserializer
199                .read_serde_setting("exempt_ips")
200                .unwrap_or_default(),
201            exempt_api_keys: deserializer
202                .read_serde_setting("exempt_api_keys")
203                .unwrap_or_default(),
204        }))
205    }
206}