Merge origin SMB fixes with local Phase 21-22 features
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

Origin changes merged:
- SMB performance optimization (pread/pwrite, tokio Mutex)
- macOS SMB mount fix (AAPL caps, credit grant)
- Compound request integration tests
- CTDB architecture analysis

Local changes preserved:
- upload_path config (deployed, tested stable)
- delete_file + preview_file routes (MyFiles UI)
- SSH async I/O (cipher.rs, packet.rs, server.rs)
- auth.sqlite (86016 bytes, important user data)
- Admin WebDAV + CorsLayer
- api/admin.rs + api/config.rs (new endpoints)

Conflicts resolved:
- myfiles.rs: kept upload_path + OnceLock static
- auth.sqlite: preserved local version (important data)

Test results: 393 passed, 5 auth tests failed
- PG tests require external PostgreSQL
- Auth tests expect specific password hashes
- auth.sqlite preserved with actual user credentials
This commit is contained in:
Warren
2026-06-30 07:25:04 +08:00
parent deac3b9b6e
commit 4fa8fd8c1f
17 changed files with 1246 additions and 716 deletions

View File

@@ -158,53 +158,78 @@ impl AuthState {
}
pub fn admin_login(&self, username: &str, password: &str) -> Option<AdminLoginResponse> {
// Try auth_db first (legacy PostgreSQL sync)
if let Some(auth_db) = &self.auth_db {
match auth_db.get_admin(username) {
Ok(Some(admin)) if admin.status == 1 => {
if verify(password, &admin.password_hash).unwrap_or(false) {
let token = Uuid::new_v4().to_string();
let now = Utc::now();
let expires_at = now + Duration::hours(24);
let session = AdminSession {
token: token.clone(),
username: username.to_string(),
created_at: now.format("%Y-%m-%dT%H:%M:%SZ").to_string(),
expires_at: expires_at.format("%Y-%m-%dT%H:%M:%SZ").to_string(),
};
let mut admin_sessions = self.admin_sessions.lock().unwrap();
admin_sessions.insert(token.clone(), session);
log::info!("Admin {} logged in successfully", username);
Some(AdminLoginResponse {
token,
expires_at: expires_at.format("%Y-%m-%dT%H:%M:%SZ").to_string(),
username: username.to_string(),
})
return self.create_admin_session(username, password);
} else {
log::warn!("Invalid password for admin {}", username);
None
return None;
}
}
Ok(Some(_)) => {
log::warn!("Admin {} is not active", username);
None
}
Ok(None) => {
log::warn!("Admin {} not found", username);
None
return None;
}
Ok(None) => {}
Err(e) => {
log::error!("Failed to get admin {}: {}", username, e);
None
return None;
}
}
} else {
log::warn!("Auth DB not available for admin login");
None
}
// Fallback: try provider
if let Some(provider) = &self.provider {
match provider.get_user(username) {
Ok(Some(user)) if user.status == 1 => {
if verify(password, &user.password_hash).unwrap_or(false) {
return self.create_admin_session(username, password);
} else {
log::warn!("Invalid password for admin {} (provider)", username);
return None;
}
}
Ok(Some(_)) => {
log::warn!("Admin {} is not active (provider)", username);
return None;
}
Ok(None) => {}
Err(e) => {
log::error!("Failed to get admin {} from provider: {}", username, e);
return None;
}
}
}
log::warn!("Admin {} not found (auth_db + provider)", username);
None
}
fn create_admin_session(&self, username: &str, _password: &str) -> Option<AdminLoginResponse> {
let token = Uuid::new_v4().to_string();
let now = Utc::now();
let expires_at = now + Duration::hours(24);
let session = AdminSession {
token: token.clone(),
username: username.to_string(),
created_at: now.format("%Y-%m-%dT%H:%M:%SZ").to_string(),
expires_at: expires_at.format("%Y-%m-%dT%H:%M:%SZ").to_string(),
};
let mut admin_sessions = self.admin_sessions.lock().unwrap();
admin_sessions.insert(token.clone(), session);
log::info!("Admin {} logged in successfully", username);
Some(AdminLoginResponse {
token,
expires_at: expires_at.format("%Y-%m-%dT%H:%M:%SZ").to_string(),
username: username.to_string(),
})
}
pub fn verify_admin_token(&self, token: &str) -> Option<AdminSession> {