fix: sync rust api-server runtime and bindings

This commit is contained in:
2026-04-23 20:32:06 +08:00
parent 9d25a47b23
commit 27e84c46a0
82 changed files with 9534 additions and 2222 deletions

View File

@@ -41,6 +41,7 @@ pub enum AuthBindingStatus {
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AuthUser {
pub id: String,
pub public_user_code: String,
pub username: String,
pub display_name: String,
pub phone_number_masked: Option<String>,
@@ -55,6 +56,11 @@ pub struct AuthMeResult {
pub user: AuthUser,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PublicUserSearchResult {
pub user: AuthUser,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PasswordEntryInput {
pub username: String,
@@ -262,6 +268,7 @@ pub struct LogoutAllSessionsResult {
pub enum PasswordEntryError {
InvalidUsername,
InvalidPasswordLength,
InvalidPublicUserCode,
InvalidCredentials,
Store(String),
PasswordHash(String),
@@ -457,6 +464,16 @@ impl PasswordEntryService {
.find_by_user_id(user_id)
.map(|maybe_user| maybe_user.map(|stored| AuthMeResult { user: stored.user }))
}
pub fn get_user_by_public_user_code(
&self,
public_user_code: &str,
) -> Result<Option<PublicUserSearchResult>, PasswordEntryError> {
let normalized_public_user_code = normalize_public_user_code(public_user_code)?;
self.store
.find_by_public_user_code(&normalized_public_user_code)
.map(|maybe_user| maybe_user.map(|stored| PublicUserSearchResult { user: stored.user }))
}
}
impl RefreshSessionService {
@@ -870,6 +887,18 @@ impl AuthUserService {
.map_err(map_password_error_to_logout_error)
}
pub fn get_user_by_public_user_code(
&self,
public_user_code: &str,
) -> Result<Option<AuthUser>, LogoutError> {
let normalized_public_user_code = normalize_public_user_code(public_user_code)
.map_err(map_password_error_to_logout_error)?;
self.store
.find_by_public_user_code(&normalized_public_user_code)
.map(|maybe_user| maybe_user.map(|stored| stored.user))
.map_err(map_password_error_to_logout_error)
}
pub fn logout_current_session(
&self,
input: LogoutCurrentSessionInput,
@@ -962,6 +991,22 @@ impl InMemoryAuthStore {
.cloned())
}
fn find_by_public_user_code(
&self,
public_user_code: &str,
) -> Result<Option<StoredPasswordUser>, PasswordEntryError> {
let state = self
.inner
.lock()
.map_err(|_| PasswordEntryError::Store("用户仓储锁已中毒".to_string()))?;
Ok(state
.users_by_username
.values()
.find(|stored_user| stored_user.user.public_user_code == public_user_code)
.cloned())
}
fn find_by_phone_number(
&self,
phone_number: &str,
@@ -994,11 +1039,14 @@ impl InMemoryAuthStore {
return Err(CreateUserError::AlreadyExists);
}
let user_id = format!("user_{:08}", state.next_user_id);
let sequence = state.next_user_id;
let user_id = format!("user_{sequence:08}");
let public_user_code = build_public_user_code(sequence);
state.next_user_id += 1;
let user = AuthUser {
id: user_id,
public_user_code,
username: username.clone(),
display_name: username.clone(),
phone_number_masked: None,
@@ -1035,11 +1083,14 @@ impl InMemoryAuthStore {
));
}
let user_id = format!("user_{:08}", state.next_user_id);
let sequence = state.next_user_id;
let user_id = format!("user_{sequence:08}");
let public_user_code = build_public_user_code(sequence);
state.next_user_id += 1;
let username = build_system_username("phone", state.next_user_id);
let user = AuthUser {
id: user_id.clone(),
public_user_code,
username: username.clone(),
display_name,
phone_number_masked: Some(phone_number.masked_national_number.clone()),
@@ -1073,7 +1124,9 @@ impl InMemoryAuthStore {
.lock()
.map_err(|_| WechatAuthError::Store("用户仓储锁已中毒".to_string()))?;
let user_id = format!("user_{:08}", state.next_user_id);
let sequence = state.next_user_id;
let user_id = format!("user_{sequence:08}");
let public_user_code = build_public_user_code(sequence);
state.next_user_id += 1;
let username = build_system_username("wechat", state.next_user_id);
let display_name = profile
@@ -1085,6 +1138,7 @@ impl InMemoryAuthStore {
.to_string();
let user = AuthUser {
id: user_id.clone(),
public_user_code,
username: username.clone(),
display_name,
phone_number_masked: None,
@@ -1722,6 +1776,7 @@ impl fmt::Display for PasswordEntryError {
match self {
Self::InvalidUsername => f.write_str("用户名只允许 3 到 24 位字母、数字、下划线"),
Self::InvalidPasswordLength => f.write_str("密码长度需要在 6 到 128 位之间"),
Self::InvalidPublicUserCode => f.write_str("叙世号格式不正确"),
Self::InvalidCredentials => f.write_str("用户名或密码错误"),
Self::Store(message) | Self::PasswordHash(message) => f.write_str(message),
}
@@ -1794,6 +1849,7 @@ fn map_password_store_error(error: PasswordEntryError) -> RefreshSessionError {
PasswordEntryError::Store(message) => RefreshSessionError::Store(message),
PasswordEntryError::InvalidUsername
| PasswordEntryError::InvalidPasswordLength
| PasswordEntryError::InvalidPublicUserCode
| PasswordEntryError::InvalidCredentials
| PasswordEntryError::PasswordHash(_) => {
RefreshSessionError::Store("用户仓储读取失败".to_string())
@@ -1807,6 +1863,7 @@ fn map_password_error_to_phone_error(error: PasswordEntryError) -> PhoneAuthErro
PasswordEntryError::PasswordHash(message) => PhoneAuthError::PasswordHash(message),
PasswordEntryError::InvalidUsername
| PasswordEntryError::InvalidPasswordLength
| PasswordEntryError::InvalidPublicUserCode
| PasswordEntryError::InvalidCredentials => {
PhoneAuthError::Store("用户仓储读取失败".to_string())
}
@@ -1818,6 +1875,7 @@ fn map_password_error_to_logout_error(error: PasswordEntryError) -> LogoutError
PasswordEntryError::Store(message) => LogoutError::Store(message),
PasswordEntryError::InvalidUsername
| PasswordEntryError::InvalidPasswordLength
| PasswordEntryError::InvalidPublicUserCode
| PasswordEntryError::InvalidCredentials
| PasswordEntryError::PasswordHash(_) => LogoutError::Store("用户仓储读取失败".to_string()),
}
@@ -1923,6 +1981,30 @@ fn build_system_username(prefix: &str, sequence: u64) -> String {
format!("{prefix}_{sequence:08}")
}
// 公开叙世号是稳定的公开检索键,不替代内部 user_id仅用于展示、分享与搜索。
fn build_public_user_code(sequence: u64) -> String {
format!("SY-{sequence:08}")
}
pub fn normalize_public_user_code(input: &str) -> Result<String, PasswordEntryError> {
let normalized = input
.trim()
.chars()
.filter(|character| character.is_ascii_alphanumeric())
.collect::<String>()
.to_ascii_uppercase();
let digits = normalized.strip_prefix("SY").unwrap_or(&normalized);
if digits.is_empty()
|| digits.len() > 8
|| !digits.chars().all(|character| character.is_ascii_digit())
{
return Err(PasswordEntryError::InvalidPublicUserCode);
}
Ok(format!("SY-{digits:0>8}"))
}
fn format_rfc3339(value: OffsetDateTime) -> Result<String, String> {
format_shared_rfc3339(value)
}