Files
markbase/markbase-sftp-poc/src/shell_handler.rs
Warren 1300a4e223
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled
MarkBase架构升级:Multi-Volume Virtual Tree + Dual-View Management + Git Remote修正
核心功能:
-  Categories/Series双视图管理(category_view.rs + import_markdown.rs)
-  FUSE Multi-Volume支持(tree_type参数)
-  SSH/SFTP/SCP/rsync协议完整实现(4042行)
-  NFS/SMB Module Phase 1-3完成
-  Archive Module Phase 1-4完成(2916行)
-  Download Center API完整实现
-  S3兼容API实现(560行)

Git配置修正:
-  删除错误origin(gitea.momentry.ddns.net)
-  删除m5max128(指向机器名)
-  设置origin = m5max128gitea.momentry.ddns.net/admin/markbase
-  设置m4minigitea = m4minigitea.momentry.ddns.net/warren/markbase

数据清理:
-  删除38个临时SQLite(保留accusys.sqlite、demo.sqlite)
-  删除.bak、test_*.bin、调试脚本等临时文件
-  删除临时目录(build/、download files/、raid_test/等)
-  更新.gitignore排除临时文件

架构优化:
- 52个文件修改,2434行新增,4739行删除
- Workspace成员整合(16个crate)
- 数据库状态:accusys.sqlite保留(主demo测试)

远程同步:
-  准备推送到m5max128gitea(远程Gitea)
-  准备推送到m4minigitea(本地Gitea)
2026-06-12 12:59:54 +08:00

144 lines
4.6 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use anyhow::{Error, Result};
use russh::server::{Auth, Session, Sig};
use russh::{ChannelId, SigId};
use tokio::process::Command;
use std::sync::Arc;
use log::{info, warn, error};
use crate::auth::MockAuthDb;
pub struct ShellSession {
auth_db: Arc<MockAuthDb>,
user: String,
}
impl ShellSession {
pub fn new(auth_db: Arc<MockAuthDb>, user: String) -> Self {
Self { auth_db, user }
}
// 关键方法exec_requestrsync使用
async fn exec_request(&mut self, channel: ChannelId, command: &str) -> Result<()> {
info!("Shell exec_request: user={}, command={}", self.user, command);
// 1. 安全检查:只允许特定命令
if !self.is_command_allowed(command) {
warn!("Command not allowed: {}", command);
return Err(Error::msg("Command not allowed"));
}
// 2. rsync命令特殊处理
if command.starts_with("rsync --server") {
return self.handle_rsync(channel, command).await;
}
// 3. 其他允许的shell命令执行
let parts: Vec<&str> = command.split_whitespace().collect();
if parts.is_empty() {
return Err(Error::msg("Empty command"));
}
let cmd = Command::new(parts[0])
.args(&parts[1..])
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()?;
// 4. 等待命令执行完成
let status = cmd.wait().await?;
info!("Command exit status: {}", status);
Ok(())
}
// 安全检查:命令白名单
fn is_command_allowed(&self, command: &str) -> bool {
// 允许的命令列表
let allowed_commands = [
"ls", "pwd", "cd", "echo", "cat", "rsync",
];
let cmd_name = command.split_whitespace().next().unwrap_or("");
allowed_commands.contains(&cmd_name)
}
// rsync命令处理核心功能
async fn handle_rsync(&mut self, channel: ChannelId, command: &str) -> Result<()> {
info!("Handling rsync command: {}", command);
// 1. 解析rsync命令
let parts: Vec<&str> = command.split_whitespace().collect();
// 2. 提取路径参数(最后一个参数)
let path = parts.last().unwrap_or(".");
// 3. 用户目录限制
let user_dir = self.auth_db.get_user_dir(&self.user);
// 4. 路径安全检查
if path.starts_with("/") && !path.starts_with(&user_dir) {
warn!("Path access denied: user={}, path={}", self.user, path);
return Err(Error::msg("Path access denied"));
}
// 5. 执行rsync命令
let mut cmd = Command::new("rsync");
cmd.args(&parts[1..parts.len()-1]) // rsync参数
.arg(&user_dir); // 替换为用户目录
let child = cmd.spawn()?;
let status = child.wait().await?;
info!("rsync exit status: {}", status);
Ok(())
}
}
// russh server Session实现
impl Session for ShellSession {
// shell子系统交互式shell
async fn shell_request(&mut self, channel: ChannelId) -> Result<()> {
info!("Shell request received for user: {}", self.user);
// 创建交互式shell进程
let shell = Command::new("/bin/bash")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()?;
shell.wait().await?;
Ok(())
}
// exec子系统执行命令rsync使用
async fn exec_request(&mut self, channel: ChannelId, command: &str) -> Result<()> {
self.exec_request(channel, command).await
}
// 信号处理
async fn signal(&mut self, channel: ChannelId, signal: Sig) -> Result<()> {
info!("Signal received: {:?}", signal);
Ok(())
}
}
// russh server Auth实现
impl Auth for ShellSession {
// 密码认证
async fn auth_password(&mut self, user: &str, password: &str) -> russh::server::AuthResult {
info!("Auth password attempt: user={}", user);
if self.auth_db.verify_password(user, password).unwrap_or(false) {
info!("Auth success: user={}", user);
russh::server::AuthResult::Accept
} else {
warn!("Auth failed: user={}", user);
russh::server::AuthResult::Reject
}
}
}