1#[cfg(feature = "mongodb")]
2mod mongodb;
3mod reference;
4
5use authifier::config::Captcha;
6use authifier::config::EmailVerificationConfig;
7use authifier::config::PasswordScanning;
8use authifier::config::ResolveIp;
9use authifier::config::SMTPSettings;
10use authifier::config::Shield;
11use authifier::config::Template;
12use authifier::config::Templates;
13use authifier::Authifier;
14use rand::Rng;
15use revolt_config::config;
16
17#[cfg(feature = "mongodb")]
18pub use self::mongodb::*;
19pub use self::reference::*;
20
21pub enum DatabaseInfo {
23 Auto,
25 Test(String),
27 Reference,
29 #[cfg(feature = "mongodb")]
31 MongoDb { uri: String, database_name: String },
32 #[cfg(feature = "mongodb")]
34 MongoDbFromClient(::mongodb::Client, String),
35}
36
37#[derive(Clone, Debug)]
39pub enum Database {
40 Reference(ReferenceDb),
42 #[cfg(feature = "mongodb")]
44 MongoDb(MongoDb),
45}
46
47impl DatabaseInfo {
48 #[async_recursion]
50 pub async fn connect(self) -> Result<Database, String> {
51 let config = config().await;
52
53 match self {
54 DatabaseInfo::Auto => {
55 if std::env::var("TEST_DB").is_ok() {
56 DatabaseInfo::Test(format!(
57 "revolt_test_{}",
58 rand::thread_rng().gen_range(1_000_000..10_000_000)
59 ))
60 .connect()
61 .await
62 } else if !config.database.mongodb.is_empty() {
63 #[cfg(feature = "mongodb")]
64 return DatabaseInfo::MongoDb {
65 uri: config.database.mongodb,
66 database_name: "revolt".to_string(),
67 }
68 .connect()
69 .await;
70
71 #[cfg(not(feature = "mongodb"))]
72 return Err("MongoDB not enabled.".to_string())
73 } else {
74 DatabaseInfo::Reference.connect().await
75 }
76 }
77 DatabaseInfo::Test(database_name) => {
78 match std::env::var("TEST_DB")
79 .expect("`TEST_DB` environment variable should be set to REFERENCE or MONGODB")
80 .as_str()
81 {
82 "REFERENCE" => DatabaseInfo::Reference.connect().await,
83 "MONGODB" => {
84 #[cfg(feature = "mongodb")]
85 return DatabaseInfo::MongoDb {
86 uri: config.database.mongodb,
87 database_name,
88 }
89 .connect()
90 .await;
91
92 #[cfg(not(feature = "mongodb"))]
93 return Err("MongoDB not enabled.".to_string())
94 }
95 _ => unreachable!("must specify REFERENCE or MONGODB"),
96 }
97 }
98 DatabaseInfo::Reference => Ok(Database::Reference(Default::default())),
99 #[cfg(feature = "mongodb")]
100 DatabaseInfo::MongoDb { uri, database_name } => {
101 let client = ::mongodb::Client::with_uri_str(uri)
102 .await
103 .map_err(|_| "Failed to init db connection.".to_string())?;
104
105 Ok(Database::MongoDb(MongoDb(client, database_name)))
106 }
107 #[cfg(feature = "mongodb")]
108 DatabaseInfo::MongoDbFromClient(client, database_name) => {
109 Ok(Database::MongoDb(MongoDb(client, database_name)))
110 }
111 }
112 }
113}
114
115impl Database {
116 pub async fn to_authifier(self) -> Authifier {
118 let config = config().await;
119
120 let mut auth_config = authifier::Config {
121 password_scanning: if config.api.security.easypwned.is_empty() {
122 Default::default()
123 } else {
124 PasswordScanning::EasyPwned {
125 endpoint: config.api.security.easypwned,
126 }
127 },
128 email_verification: if !config.api.smtp.host.is_empty() {
129 EmailVerificationConfig::Enabled {
130 smtp: SMTPSettings {
131 from: config.api.smtp.from_address,
132 host: config.api.smtp.host,
133 username: config.api.smtp.username,
134 password: config.api.smtp.password,
135 reply_to: Some(
136 config
137 .api
138 .smtp
139 .reply_to
140 .unwrap_or("support@revolt.chat".into()),
141 ),
142 port: config.api.smtp.port,
143 use_tls: config.api.smtp.use_tls,
144 use_starttls: config.api.smtp.use_starttls,
145 },
146 expiry: Default::default(),
147 templates: if config.production {
148 Templates {
149 verify: Template {
150 title: "Verify your Revolt account.".into(),
151 text: include_str!("../../templates/verify.txt").into(),
152 url: format!("{}/login/verify/", config.hosts.app),
153 html: Some(include_str!("../../templates/verify.html").into()),
154 },
155 reset: Template {
156 title: "Reset your Revolt password.".into(),
157 text: include_str!("../../templates/reset.txt").into(),
158 url: format!("{}/login/reset/", config.hosts.app),
159 html: Some(include_str!("../../templates/reset.html").into()),
160 },
161 reset_existing: Template {
162 title: "You already have a Revolt account, reset your password."
163 .into(),
164 text: include_str!("../../templates/reset-existing.txt").into(),
165 url: format!("{}/login/reset/", config.hosts.app),
166 html: Some(
167 include_str!("../../templates/reset-existing.html").into(),
168 ),
169 },
170 deletion: Template {
171 title: "Confirm account deletion.".into(),
172 text: include_str!("../../templates/deletion.txt").into(),
173 url: format!("{}/delete/", config.hosts.app),
174 html: Some(include_str!("../../templates/deletion.html").into()),
175 },
176 welcome: None,
177 }
178 } else {
179 Templates {
180 verify: Template {
181 title: "Verify your account.".into(),
182 text: include_str!("../../templates/verify.whitelabel.txt").into(),
183 url: format!("{}/login/verify/", config.hosts.app),
184 html: None,
185 },
186 reset: Template {
187 title: "Reset your password.".into(),
188 text: include_str!("../../templates/reset.whitelabel.txt").into(),
189 url: format!("{}/login/reset/", config.hosts.app),
190 html: None,
191 },
192 reset_existing: Template {
193 title: "Reset your password.".into(),
194 text: include_str!("../../templates/reset.whitelabel.txt").into(),
195 url: format!("{}/login/reset/", config.hosts.app),
196 html: None,
197 },
198 deletion: Template {
199 title: "Confirm account deletion.".into(),
200 text: include_str!("../../templates/deletion.whitelabel.txt")
201 .into(),
202 url: format!("{}/delete/", config.hosts.app),
203 html: None,
204 },
205 welcome: None,
206 }
207 },
208 }
209 } else {
210 EmailVerificationConfig::Disabled
211 },
212 ..Default::default()
213 };
214
215 auth_config.invite_only = config.api.registration.invite_only;
216
217 if !config.api.security.captcha.hcaptcha_key.is_empty() {
218 auth_config.captcha = Captcha::HCaptcha {
219 secret: config.api.security.captcha.hcaptcha_key,
220 };
221 }
222
223 if !config.api.security.authifier_shield_key.is_empty() {
224 auth_config.shield = Shield::Enabled {
225 api_key: config.api.security.authifier_shield_key,
226 strict: false,
227 };
228 }
229
230 if config.api.security.trust_cloudflare {
231 auth_config.resolve_ip = ResolveIp::Cloudflare;
232 }
233
234 Authifier {
235 database: match self {
236 Database::Reference(_) => Default::default(),
237 #[cfg(feature = "mongodb")]
238 Database::MongoDb(MongoDb(client, _)) => authifier::Database::MongoDb(
239 authifier::database::MongoDb(client.database("revolt")),
240 ),
241 },
242 config: auth_config,
243 #[cfg(feature = "tasks")]
244 event_channel: Some(crate::tasks::authifier_relay::sender()),
245 #[cfg(not(feature = "tasks"))]
246 event_channel: None,
247 }
248 }
249}