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.
|
# 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:
|
# Examples of delegation:
|
||||||
# - https://continuwuity.org/.well-known/matrix/server
|
# - https://continuwuity.org/.well-known/matrix/server
|
||||||
# - https://continuwuity.org/.well-known/matrix/client
|
# - https://continuwuity.org/.well-known/matrix/client
|
||||||
|
|
|
||||||
|
|
@ -296,6 +296,29 @@ pub(super) async fn reset_password(
|
||||||
Ok(())
|
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]
|
#[admin_command]
|
||||||
pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) -> Result {
|
pub(super) async fn deactivate_all(&self, no_leave_rooms: bool, force: bool) -> Result {
|
||||||
if self.body.len() < 2
|
if self.body.len() < 2
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,12 @@ pub enum UserCommand {
|
||||||
password: Option<String>,
|
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
|
/// Deactivate a user
|
||||||
///
|
///
|
||||||
/// User will be removed from all rooms by default.
|
/// 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.
|
/// 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:
|
/// Examples of delegation:
|
||||||
/// - https://continuwuity.org/.well-known/matrix/server
|
/// - https://continuwuity.org/.well-known/matrix/server
|
||||||
/// - https://continuwuity.org/.well-known/matrix/client
|
/// - https://continuwuity.org/.well-known/matrix/client
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ pub(super) static MAPS: &[Descriptor] = &[
|
||||||
..descriptor::RANDOM_SMALL
|
..descriptor::RANDOM_SMALL
|
||||||
},
|
},
|
||||||
Descriptor {
|
Descriptor {
|
||||||
name: "passwordresettoken_userid",
|
name: "passwordresettoken_info",
|
||||||
..descriptor::RANDOM_SMALL
|
..descriptor::RANDOM_SMALL
|
||||||
},
|
},
|
||||||
Descriptor {
|
Descriptor {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use conduwuit::{
|
||||||
config::{Config, check},
|
config::{Config, check},
|
||||||
error, implement,
|
error, implement,
|
||||||
};
|
};
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
use crate::registration_tokens::{ValidToken, ValidTokenSource};
|
use crate::registration_tokens::{ValidToken, ValidTokenSource};
|
||||||
|
|
||||||
|
|
@ -23,6 +24,18 @@ impl Service {
|
||||||
.clone()
|
.clone()
|
||||||
.map(|token| ValidToken { token, source: ValidTokenSource::Config })
|
.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]
|
#[async_trait]
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ use ruma::OwnedUserId;
|
||||||
|
|
||||||
use crate::{Dep, globals, users};
|
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;
|
const RESET_TOKEN_LENGTH: usize = 32;
|
||||||
|
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
|
|
@ -52,6 +54,10 @@ impl Service {
|
||||||
return Err!("Cannot issue a password reset token for remote user {user}");
|
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" {
|
if self.services.users.origin(&user).await? != "password" {
|
||||||
return Err!("Cannot issue a password reset token for non-internal user {user}");
|
return Err!("Cannot issue a password reset token for non-internal user {user}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue