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