mirror of
https://gitlab.com/famedly/conduit.git
synced 2024-11-17 02:38:18 -07:00
feat: support user password resets
This commit is contained in:
parent
1ce03059a0
commit
ada07de204
@ -68,6 +68,8 @@ pub struct Config {
|
|||||||
#[serde(default = "default_turn_ttl")]
|
#[serde(default = "default_turn_ttl")]
|
||||||
pub turn_ttl: u64,
|
pub turn_ttl: u64,
|
||||||
|
|
||||||
|
pub emergency_password: Option<String>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub catchall: BTreeMap<String, IgnoredAny>,
|
pub catchall: BTreeMap<String, IgnoredAny>,
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,14 @@ use abstraction::DatabaseEngine;
|
|||||||
use directories::ProjectDirs;
|
use directories::ProjectDirs;
|
||||||
use futures_util::{stream::FuturesUnordered, StreamExt};
|
use futures_util::{stream::FuturesUnordered, StreamExt};
|
||||||
use lru_cache::LruCache;
|
use lru_cache::LruCache;
|
||||||
use ruma::{DeviceId, EventId, RoomId, UserId};
|
use ruma::{
|
||||||
|
events::{
|
||||||
|
push_rules::PushRulesEventContent, room::message::RoomMessageEventContent, EventType,
|
||||||
|
GlobalAccountDataEvent,
|
||||||
|
},
|
||||||
|
push::Ruleset,
|
||||||
|
DeviceId, EventId, RoomId, UserId,
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashMap, HashSet},
|
collections::{BTreeMap, HashMap, HashSet},
|
||||||
fs::{self, remove_dir_all},
|
fs::{self, remove_dir_all},
|
||||||
@ -747,6 +754,23 @@ impl Database {
|
|||||||
guard.rooms.edus.presenceid_presence.clear()?;
|
guard.rooms.edus.presenceid_presence.clear()?;
|
||||||
|
|
||||||
guard.admin.start_handler(Arc::clone(&db), admin_receiver);
|
guard.admin.start_handler(Arc::clone(&db), admin_receiver);
|
||||||
|
|
||||||
|
// Set emergency access for the conduit user
|
||||||
|
match set_emergency_access(&guard) {
|
||||||
|
Ok(pwd_set) => {
|
||||||
|
if pwd_set {
|
||||||
|
warn!("The Conduit account emergency password is set! Please unset it as soon as you finish admin account recovery!");
|
||||||
|
guard.admin.send_message(RoomMessageEventContent::text_plain("The Conduit account emergency password is set! Please unset it as soon as you finish admin account recovery!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
"Could not set the configured emergency password for the conduit user: {}",
|
||||||
|
e
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
guard
|
guard
|
||||||
.sending
|
.sending
|
||||||
.start_handler(Arc::clone(&db), sending_receiver);
|
.start_handler(Arc::clone(&db), sending_receiver);
|
||||||
@ -928,6 +952,32 @@ impl Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the emergency password and push rules for the @conduit account in case emergency password is set
|
||||||
|
fn set_emergency_access(db: &Database) -> Result<bool> {
|
||||||
|
let conduit_user = UserId::parse_with_server_name("conduit", db.globals.server_name())
|
||||||
|
.expect("@conduit:server_name is a valid UserId");
|
||||||
|
|
||||||
|
db.users
|
||||||
|
.set_password(&conduit_user, db.globals.emergency_password().as_deref())?;
|
||||||
|
|
||||||
|
let (ruleset, res) = match db.globals.emergency_password() {
|
||||||
|
Some(_) => (Ruleset::server_default(&conduit_user), Ok(true)),
|
||||||
|
None => (Ruleset::new(), Ok(false)),
|
||||||
|
};
|
||||||
|
|
||||||
|
db.account_data.update(
|
||||||
|
None,
|
||||||
|
&conduit_user,
|
||||||
|
EventType::PushRules,
|
||||||
|
&GlobalAccountDataEvent {
|
||||||
|
content: PushRulesEventContent { global: ruleset },
|
||||||
|
},
|
||||||
|
&db.globals,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DatabaseGuard(OwnedRwLockReadGuard<Database>);
|
pub struct DatabaseGuard(OwnedRwLockReadGuard<Database>);
|
||||||
|
|
||||||
impl Deref for DatabaseGuard {
|
impl Deref for DatabaseGuard {
|
||||||
|
@ -8,7 +8,7 @@ use std::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
pdu::PduBuilder,
|
pdu::PduBuilder,
|
||||||
server_server,
|
server_server, utils,
|
||||||
utils::HtmlEscape,
|
utils::HtmlEscape,
|
||||||
Database, PduEvent,
|
Database, PduEvent,
|
||||||
};
|
};
|
||||||
@ -262,6 +262,12 @@ enum AdminCommand {
|
|||||||
|
|
||||||
/// Show configuration values
|
/// Show configuration values
|
||||||
ShowConfig,
|
ShowConfig,
|
||||||
|
|
||||||
|
/// Reset user password
|
||||||
|
ResetPassword {
|
||||||
|
/// Username of the user for whom the password should be reset
|
||||||
|
username: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_admin_command(
|
fn process_admin_command(
|
||||||
@ -435,6 +441,45 @@ fn process_admin_command(
|
|||||||
// Construct and send the response
|
// Construct and send the response
|
||||||
RoomMessageEventContent::text_plain(format!("{}", db.globals.config))
|
RoomMessageEventContent::text_plain(format!("{}", db.globals.config))
|
||||||
}
|
}
|
||||||
|
AdminCommand::ResetPassword { username } => {
|
||||||
|
let user_id = match UserId::parse_with_server_name(
|
||||||
|
username.as_str().to_lowercase(),
|
||||||
|
db.globals.server_name(),
|
||||||
|
) {
|
||||||
|
Ok(id) => id,
|
||||||
|
Err(e) => {
|
||||||
|
return Ok(RoomMessageEventContent::text_plain(format!(
|
||||||
|
"The supplied username is not a valid username: {}",
|
||||||
|
e
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the specified user is valid
|
||||||
|
if !db.users.exists(&user_id)?
|
||||||
|
|| db.users.is_deactivated(&user_id)?
|
||||||
|
|| user_id
|
||||||
|
== UserId::parse_with_server_name("conduit", db.globals.server_name())
|
||||||
|
.expect("conduit user exists")
|
||||||
|
{
|
||||||
|
return Ok(RoomMessageEventContent::text_plain(
|
||||||
|
"The specified user does not exist or is deactivated!",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_password = utils::random_string(20);
|
||||||
|
|
||||||
|
match db.users.set_password(&user_id, Some(new_password.as_str())) {
|
||||||
|
Ok(()) => RoomMessageEventContent::text_plain(format!(
|
||||||
|
"Successfully reset the password for user {}: {}",
|
||||||
|
user_id, new_password
|
||||||
|
)),
|
||||||
|
Err(e) => RoomMessageEventContent::text_plain(format!(
|
||||||
|
"Couldn't reset the password for user {}: {}",
|
||||||
|
user_id, e
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(reply_message_content)
|
Ok(reply_message_content)
|
||||||
|
@ -264,6 +264,10 @@ impl Globals {
|
|||||||
&self.config.turn_secret
|
&self.config.turn_secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn emergency_password(&self) -> &Option<String> {
|
||||||
|
&self.config.emergency_password
|
||||||
|
}
|
||||||
|
|
||||||
/// TODO: the key valid until timestamp is only honored in room version > 4
|
/// TODO: the key valid until timestamp is only honored in room version > 4
|
||||||
/// Remove the outdated keys and insert the new ones.
|
/// Remove the outdated keys and insert the new ones.
|
||||||
///
|
///
|
||||||
|
@ -1491,7 +1491,11 @@ impl Rooms {
|
|||||||
let server_user = format!("@conduit:{}", db.globals.server_name());
|
let server_user = format!("@conduit:{}", db.globals.server_name());
|
||||||
|
|
||||||
let to_conduit = body.starts_with(&format!("{}: ", server_user));
|
let to_conduit = body.starts_with(&format!("{}: ", server_user));
|
||||||
let from_conduit = pdu.sender == server_user;
|
|
||||||
|
// This will evaluate to false if the emergency password is set up so that
|
||||||
|
// the administrator can execute commands as conduit
|
||||||
|
let from_conduit =
|
||||||
|
pdu.sender == server_user && db.globals.emergency_password().is_none();
|
||||||
|
|
||||||
if to_conduit && !from_conduit && admin_room.as_ref() == Some(&pdu.room_id) {
|
if to_conduit && !from_conduit && admin_room.as_ref() == Some(&pdu.room_id) {
|
||||||
db.admin.process_message(body.to_string());
|
db.admin.process_message(body.to_string());
|
||||||
|
Loading…
Reference in New Issue
Block a user