Identity: a password reset for a known address that fails to save or send is logged, never answered, so the reply never says an account exists
1 file+15−20/1 viewed
| 240 | 240 | None => true, | |
| 241 | 241 | }; | |
| 242 | 242 | if allowed && let Some(target) = self.reset_target(&a.email).await? { | |
| 243 | + | // A failure from here on happens only for a real account, so it | |
| 244 | + | // is logged, never answered: the reply below stays the same. | |
| 245 | + | if let Err(error) = self.send_reset(&target).await { | |
| 246 | + | worker::console_error!("password reset for a known address failed: {error}"); | |
| 247 | + | } | |
| 248 | + | } | |
| 249 | + | // The same answer either way, so addresses cannot be probed. | |
| 250 | + | Ok(true) | |
| 251 | + | } | |
| 252 | + | ||
| 253 | + | /// Saves a reset link for `target` and mails it, telling the account's | |
| 254 | + | /// other addresses. | |
| 255 | + | async fn send_reset(&self, target: &emails::ResetTarget) -> Result<()> { | |
| 256 | + | { | |
| 243 | 257 | let token = crypto::random_hex(32); | |
| 244 | 258 | self.db | |
| 245 | 259 | .prepare(format!( | |
| 264 | 278 | } | |
| 265 | 279 | } | |
| 266 | 280 | } | |
| 267 | − | // The same answer either way, so addresses cannot be probed. | |
| 268 | − | Ok(true) | |
| 281 | + | Ok(()) | |
| 269 | 282 | } | |
| 270 | 283 | ||
| 271 | 284 | async fn reset_password(&self, a: ResetPasswordArgs) -> Result<Outcome<User>> { |