fix: sync rust api-server runtime and bindings
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user