feat: Implement a command for issuing password reset links
This commit is contained in:
parent
267feb3c09
commit
da8833fca4
7 changed files with 56 additions and 1 deletions
|
|
@ -25,6 +25,9 @@
|
|||
#
|
||||
# Also see the `[global.well_known]` config section at the very bottom.
|
||||
#
|
||||
# If `client` is not set under `[global.well_known]`, the server name will be used
|
||||
# as the base domain for user-facing links (such as password reset links) created by Continuwuity.
|
||||
#
|
||||
# Examples of delegation:
|
||||
# - https://continuwuity.org/.well-known/matrix/server
|
||||
# - https://continuwuity.org/.well-known/matrix/client
|
||||
|
|
|
|||
|
|
@ -296,6 +296,29 @@ pub(super) async fn reset_password(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn issue_password_reset_link(&self, username: String) -> Result {
|
||||
use conduwuit_service::password_reset::{PASSWORD_RESET_PATH, RESET_TOKEN_QUERY_PARAM};
|
||||
|
||||
let mut reset_url = self
|
||||
.services
|
||||
.config
|
||||
.get_client_domain()
|
||||
.join(PASSWORD_RESET_PATH)
|
||||
.unwrap();
|
||||
|
||||
let user_id = parse_local_user_id(self.services, &username)?;
|
||||
let token = self.services.password_reset.issue_token(user_id).await?;
|
||||
reset_url
|
||||
.query_pairs_mut()
|
||||
.append_pair(RESET_TOKEN_QUERY_PARAM, &token.token);
|
||||
|
||||
self.write_str(&format!("Password reset link issued for {username}: {reset_url}"))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[admin_command]
|
||||
pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) -> Result {
|
||||
if self.body.len() < 2
|
||||
|
|
|
|||
|
|
@ -29,6 +29,12 @@ pub enum UserCommand {
|
|||
password: Option<String>,
|
||||
},
|
||||
|
||||
/// Issue a self-service password reset link for a user.
|
||||
IssuePasswordResetLink {
|
||||
/// Username of the user who may use the link
|
||||
username: String,
|
||||
},
|
||||
|
||||
/// Deactivate a user
|
||||
///
|
||||
/// User will be removed from all rooms by default.
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ pub struct Config {
|
|||
///
|
||||
/// Also see the `[global.well_known]` config section at the very bottom.
|
||||
///
|
||||
/// If `client` is not set under `[global.well_known]`, the server name will
|
||||
/// be used as the base domain for user-facing links (such as password
|
||||
/// reset links) created by Continuwuity.
|
||||
///
|
||||
/// Examples of delegation:
|
||||
/// - https://continuwuity.org/.well-known/matrix/server
|
||||
/// - https://continuwuity.org/.well-known/matrix/client
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ pub(super) static MAPS: &[Descriptor] = &[
|
|||
..descriptor::RANDOM_SMALL
|
||||
},
|
||||
Descriptor {
|
||||
name: "passwordresettoken_userid",
|
||||
name: "passwordresettoken_info",
|
||||
..descriptor::RANDOM_SMALL
|
||||
},
|
||||
Descriptor {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use conduwuit::{
|
|||
config::{Config, check},
|
||||
error, implement,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
use crate::registration_tokens::{ValidToken, ValidTokenSource};
|
||||
|
||||
|
|
@ -23,6 +24,18 @@ impl Service {
|
|||
.clone()
|
||||
.map(|token| ValidToken { token, source: ValidTokenSource::Config })
|
||||
}
|
||||
|
||||
/// Get the base domain to use for user-facing URLs.
|
||||
#[must_use]
|
||||
pub fn get_client_domain(&self) -> Url {
|
||||
self.well_known.client.clone().unwrap_or_else(|| {
|
||||
let host = self.server_name.host();
|
||||
format!("https://{host}")
|
||||
.as_str()
|
||||
.try_into()
|
||||
.expect("server name should be a valid host")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ use ruma::OwnedUserId;
|
|||
|
||||
use crate::{Dep, globals, users};
|
||||
|
||||
pub const PASSWORD_RESET_PATH: &str = "/_continuwuity/password_reset";
|
||||
pub const RESET_TOKEN_QUERY_PARAM: &str = "token";
|
||||
const RESET_TOKEN_LENGTH: usize = 32;
|
||||
|
||||
pub struct Service {
|
||||
|
|
@ -52,6 +54,10 @@ impl Service {
|
|||
return Err!("Cannot issue a password reset token for remote user {user}");
|
||||
}
|
||||
|
||||
if user == self.services.globals.server_user {
|
||||
return Err!("Cannot issue a password reset token for the server user");
|
||||
}
|
||||
|
||||
if self.services.users.origin(&user).await? != "password" {
|
||||
return Err!("Cannot issue a password reset token for non-internal user {user}");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue