feat: reset the login password #126

This commit is contained in:
rustmailer
2026-01-22 13:19:21 +08:00
parent 579801ef5c
commit 694e5ecbec
9 changed files with 473 additions and 75 deletions
+111
View File
@@ -0,0 +1,111 @@
use std::{path::Path, rc::Rc};
use native_db::{Builder, Database};
use crate::{
modules::{
database::META_MODELS,
error::{code::ErrorCode, BichonResult},
token::{AccessTokenModel, AccessTokenModelKey, TokenType},
users::{UserModel, DEFAULT_ADMIN_USER_ID},
utils::encrypt::internal_encrypt_string,
},
raise_error,
};
use itertools::Itertools;
pub fn init_meta_database(path: impl AsRef<Path>) -> BichonResult<Rc<Database<'static>>> {
let database = Builder::new()
.set_cache_size(134217728)
.create(&META_MODELS, path)
.map_err(|e| {
raise_error!(
format!("Failed to open database: {:?}", e),
ErrorCode::InternalError
)
})?;
Ok(Rc::new(database))
}
pub fn find_admin(database: &Rc<Database<'static>>) -> BichonResult<Option<UserModel>> {
let r_transaction = database
.r_transaction()
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
let entity: Option<UserModel> = r_transaction
.get()
.primary(DEFAULT_ADMIN_USER_ID)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
return Ok(entity);
}
pub fn update_admin_password(
database: &Rc<Database<'static>>,
password: String,
encrypt_key: &str,
) -> BichonResult<()> {
let rw_transaction = database
.rw_transaction()
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
let entity: UserModel = rw_transaction
.get()
.primary(DEFAULT_ADMIN_USER_ID)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?
.ok_or_else(|| raise_error!("admin is not found".into(), ErrorCode::InternalError))?;
let mut updated = entity.clone();
updated.password = Some(
internal_encrypt_string(encrypt_key, &password)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?,
);
rw_transaction
.update(entity, updated)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
rw_transaction
.commit()
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
return Ok(());
}
pub fn reset_webui_token(database: &Rc<Database<'static>>) -> BichonResult<()> {
let rw_transaction = database
.rw_transaction()
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
let tokens: Vec<AccessTokenModel> = rw_transaction
.scan()
.secondary(AccessTokenModelKey::user_id)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?
.start_with(DEFAULT_ADMIN_USER_ID)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?
.try_collect()
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
let webui_token = tokens
.into_iter()
.find(|t| t.token_type == TokenType::WebUI);
let new_token = AccessTokenModel::new_webui_token(DEFAULT_ADMIN_USER_ID);
match webui_token {
Some(current) => {
rw_transaction
.remove(current)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
rw_transaction
.insert(new_token)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
}
None => {
rw_transaction
.insert(new_token)
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
}
}
rw_transaction
.commit()
.map_err(|e| raise_error!(format!("{:#?}", e), ErrorCode::InternalError))?;
Ok(())
}
+1
View File
@@ -0,0 +1 @@
pub mod meta;
+1
View File
@@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::bichon_version;
pub mod admin;
pub mod auth;
pub mod eml;
pub mod mbox;
+1 -3
View File
@@ -16,17 +16,15 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
use crate::modules::settings::cli::Settings;
use poem_openapi::Object;
use serde::{Deserialize, Serialize};
use crate::modules::settings::cli::Settings;
pub mod cli;
pub mod dir;
pub mod io;
pub mod proxy;
pub mod system;
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize, Object)]
pub struct SystemConfigurations {
pub bichon_log_level: String,
-1
View File
@@ -498,7 +498,6 @@ impl BichonUserV2 {
pub async fn update(id: u64, request: UserUpdateRequest) -> BichonResult<()> {
let _ = &request.validate().await?;
let password_changed = request.password.is_some();
//
let is_default_admin = id == DEFAULT_ADMIN_USER_ID;
if is_default_admin {
+2 -2
View File
@@ -72,7 +72,7 @@ pub fn decrypt_string(data: &str) -> BichonResult<String> {
})
}
fn internal_encrypt_string(
pub fn internal_encrypt_string(
password: &str,
plaintext: &str,
) -> Result<String, ring::error::Unspecified> {
@@ -102,7 +102,7 @@ fn internal_encrypt_string(
Ok(general_purpose::URL_SAFE.encode(&result))
}
fn internal_decrypt_string(password: &str, data: &str) -> Result<String, ring::error::Unspecified> {
pub fn internal_decrypt_string(password: &str, data: &str) -> Result<String, ring::error::Unspecified> {
let data = general_purpose::URL_SAFE
.decode(data)
.map_err(|_| ring::error::Unspecified)?;