license and some functions
This commit is contained in:
+12
-1
@@ -1,3 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Mateusz Gruszczyński @linuxiarz.pl
|
||||
* Source-Available Code / Dual-Licensed.
|
||||
*
|
||||
* Free for non-commercial and evaluation use under terms of BSL/GPLv3.
|
||||
* Commercial or production use requires a valid paid license.
|
||||
* See LICENSE file in repository root for details.
|
||||
*/
|
||||
|
||||
use chrono::Utc;
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
@@ -316,7 +325,9 @@ async fn sync_directory_user(
|
||||
identity: &LdapIdentity,
|
||||
email: &str,
|
||||
) -> Result<User, AuthError> {
|
||||
let nickname = available_directory_nickname(state, &identity.nickname, Some(user.id)).await?;
|
||||
// Nickname is user-managed after provisioning. Directory synchronization must not
|
||||
// overwrite a custom value on every LDAP/AD login.
|
||||
let nickname = user.nickname.clone();
|
||||
sqlx::query(queries::get(
|
||||
state.db.kind(),
|
||||
queries::AUTH_UPDATE_DIRECTORY_USER,
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Mateusz Gruszczyński @linuxiarz.pl
|
||||
* Source-Available Code / Dual-Licensed.
|
||||
*
|
||||
* Free for non-commercial and evaluation use under terms of BSL/GPLv3.
|
||||
* Commercial or production use requires a valid paid license.
|
||||
* See LICENSE file in repository root for details.
|
||||
*/
|
||||
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::state::SharedState;
|
||||
|
||||
+51
-31
@@ -1,3 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Mateusz Gruszczyński @linuxiarz.pl
|
||||
* Source-Available Code / Dual-Licensed.
|
||||
*
|
||||
* Free for non-commercial and evaluation use under terms of BSL/GPLv3.
|
||||
* Commercial or production use requires a valid paid license.
|
||||
* See LICENSE file in repository root for details.
|
||||
*/
|
||||
|
||||
pub(crate) mod ldap;
|
||||
mod local;
|
||||
|
||||
@@ -632,9 +641,16 @@ fn suggested_directory_nickname(display_name: Option<&str>, email: &str) -> Opti
|
||||
.filter(|word| !word.is_empty())
|
||||
.collect();
|
||||
if words.len() >= 2 {
|
||||
let first = words.first().copied().unwrap_or_default();
|
||||
let first = words
|
||||
.first()
|
||||
.and_then(|word| word.chars().next())
|
||||
.unwrap_or('u');
|
||||
let last = words.last().copied().unwrap_or_default();
|
||||
let candidate = format!("{}.{}", first, last).to_lowercase();
|
||||
let candidate: String = format!("{first}.{last}")
|
||||
.to_lowercase()
|
||||
.chars()
|
||||
.take(MAX_NICKNAME)
|
||||
.collect();
|
||||
if let Ok(value) = validate_nickname(&candidate) {
|
||||
return Some(value);
|
||||
}
|
||||
@@ -644,7 +660,14 @@ fn suggested_directory_nickname(display_name: Option<&str>, email: &str) -> Opti
|
||||
.split('@')
|
||||
.next()
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
.and_then(|value| validate_nickname(&value.to_lowercase()).ok())
|
||||
.map(|value| {
|
||||
value
|
||||
.to_lowercase()
|
||||
.chars()
|
||||
.take(MAX_NICKNAME)
|
||||
.collect::<String>()
|
||||
})
|
||||
.and_then(|value| validate_nickname(&value).ok())
|
||||
}
|
||||
|
||||
pub async fn me(
|
||||
@@ -842,11 +865,14 @@ pub async fn confirm_account_action(
|
||||
) -> Result<Json<serde_json::Value>, AuthError> {
|
||||
let now = Utc::now();
|
||||
let hash = hash_token(req.token.trim());
|
||||
let row = sqlx::query(queries::get(state.db.kind(), queries::AUTH_ACCOUNT_ACTION_BY_TOKEN))
|
||||
.bind(&hash)
|
||||
.fetch_optional(state.db.pool())
|
||||
.await
|
||||
.map_err(AuthError::database)?;
|
||||
let row = sqlx::query(queries::get(
|
||||
state.db.kind(),
|
||||
queries::AUTH_ACCOUNT_ACTION_BY_TOKEN,
|
||||
))
|
||||
.bind(&hash)
|
||||
.fetch_optional(state.db.pool())
|
||||
.await
|
||||
.map_err(AuthError::database)?;
|
||||
let row = row.ok_or_else(|| {
|
||||
AuthError::bad_request("The confirmation link is invalid or has expired.")
|
||||
})?;
|
||||
@@ -890,14 +916,12 @@ pub async fn confirm_account_action(
|
||||
.map_err(AuthError::database)?;
|
||||
"E-mail address changed."
|
||||
} else if action == "delete" {
|
||||
let original_nickname: Option<String> = sqlx::query_scalar(queries::get(
|
||||
state.db.kind(),
|
||||
queries::AUTH_NICKNAME_BY_ID,
|
||||
))
|
||||
.bind(user_id)
|
||||
.fetch_optional(&mut *tx)
|
||||
.await
|
||||
.map_err(AuthError::database)?;
|
||||
let original_nickname: Option<String> =
|
||||
sqlx::query_scalar(queries::get(state.db.kind(), queries::AUTH_NICKNAME_BY_ID))
|
||||
.bind(user_id)
|
||||
.fetch_optional(&mut *tx)
|
||||
.await
|
||||
.map_err(AuthError::database)?;
|
||||
let deleted_nickname = format!("Deleted user #{user_id}");
|
||||
if let Some(original_nickname) = original_nickname {
|
||||
sqlx::query(queries::get(
|
||||
@@ -920,20 +944,17 @@ pub async fn confirm_account_action(
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(AuthError::database)?;
|
||||
sqlx::query(queries::get(
|
||||
state.db.kind(),
|
||||
queries::AUTH_ANONYMIZE_USER,
|
||||
))
|
||||
.bind(&deleted_nickname)
|
||||
.bind(normalize(&deleted_nickname))
|
||||
.bind(&deleted_email)
|
||||
.bind(normalize(&deleted_email))
|
||||
.bind(deleted_password)
|
||||
.bind(now.to_rfc3339())
|
||||
.bind(user_id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(AuthError::database)?;
|
||||
sqlx::query(queries::get(state.db.kind(), queries::AUTH_ANONYMIZE_USER))
|
||||
.bind(&deleted_nickname)
|
||||
.bind(normalize(&deleted_nickname))
|
||||
.bind(&deleted_email)
|
||||
.bind(normalize(&deleted_email))
|
||||
.bind(deleted_password)
|
||||
.bind(now.to_rfc3339())
|
||||
.bind(user_id)
|
||||
.execute(&mut *tx)
|
||||
.await
|
||||
.map_err(AuthError::database)?;
|
||||
"Account deleted. Content has been preserved under an anonymized owner."
|
||||
} else {
|
||||
return Err(AuthError::bad_request("Unknown account action."));
|
||||
@@ -1945,7 +1966,6 @@ async fn find_user_by_external_id(
|
||||
.map_err(AuthError::database)
|
||||
}
|
||||
|
||||
|
||||
async fn find_user_by_share_identifier(
|
||||
state: &SharedState,
|
||||
identifier: &str,
|
||||
|
||||
Reference in New Issue
Block a user