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}