summaryrefslogtreecommitdiff
path: root/crates/vcs_actions/src/actions.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-01-02 02:22:01 +0800
committer魏曹先生 <1992414357@qq.com>2026-01-02 02:22:01 +0800
commitf6a918848b499b9ec6fab8124d714d64af8afae2 (patch)
treee7dab039d511d5ec17310af916fa941da4a9374f /crates/vcs_actions/src/actions.rs
parent8644ba2ea292ef2aa3d49976f4f3916b7ecde938 (diff)
Add host mode authentication and reference sheet handling
- Return host mode status from auth_member to determine admin privileges - Add reference sheet detection to get_current_sheet_name with allow_ref parameter - Prevent modifications to reference sheets unless in host mode - Use VAULT_HOST_NAME as sheet holder for host mode operations - Add share/merge share action registrations
Diffstat (limited to 'crates/vcs_actions/src/actions.rs')
-rw-r--r--crates/vcs_actions/src/actions.rs122
1 files changed, 96 insertions, 26 deletions
diff --git a/crates/vcs_actions/src/actions.rs b/crates/vcs_actions/src/actions.rs
index 260a6be..50281c9 100644
--- a/crates/vcs_actions/src/actions.rs
+++ b/crates/vcs_actions/src/actions.rs
@@ -5,9 +5,9 @@ use cfg_file::config::ConfigFile;
use tcp_connection::{error::TcpTargetError, instance::ConnectionInstance};
use tokio::sync::{Mutex, mpsc::Sender};
use vcs_data::{
- constants::SERVER_PATH_MEMBER_PUB,
+ constants::{SERVER_PATH_MEMBER_PUB, VAULT_HOST_NAME},
data::{
- local::{LocalWorkspace, config::LocalConfig},
+ local::{LocalWorkspace, config::LocalConfig, latest_info::LatestInfo},
member::MemberId,
sheet::SheetName,
user::UserDirectory,
@@ -78,13 +78,25 @@ pub fn try_get_local_output(ctx: &ActionContext) -> Result<Arc<Sender<String>>,
pub async fn auth_member(
ctx: &ActionContext,
instance: &Arc<Mutex<ConnectionInstance>>,
-) -> Result<MemberId, TcpTargetError> {
+) -> Result<(MemberId, bool), TcpTargetError> {
+ // Window开服Linux连接 -> 此函数内产生 early eof
+ // ~ WS # jv update
+ // 身份认证失败:I/O error: early eof!
+
+ // 分析相应流程:
+ // 1. 服务端发起挑战,客户端接受
+ // 2. 服务端发送结果,客户端接受
+ // 3. 推测此时发生 early eof ---> 无 ack,导致客户端尝试拿到结果时,服务端已经结束
+ // 这很有可能是 Windows 和 Linux 对于连接处理的方案差异导致的问题,需要进一步排查
+
// Start Challenge (Remote)
if ctx.is_proc_on_remote() {
+ let mut mut_instance = instance.lock().await;
let vault = try_get_vault(ctx)?;
- let result = instance
- .lock()
- .await
+
+ let using_host_mode = mut_instance.read_msgpack::<bool>().await?;
+
+ let result = mut_instance
.challenge(vault.vault_path().join(SERVER_PATH_MEMBER_PUB))
.await;
@@ -92,14 +104,28 @@ pub async fn auth_member(
Ok((pass, member_id)) => {
if !pass {
// Send false to inform the client that authentication failed
- instance.lock().await.write(false).await?;
+ mut_instance.write(false).await?;
Err(TcpTargetError::Authentication(
"Authenticate failed.".to_string(),
))
} else {
- // Send true to inform the client that authentication was successful
- instance.lock().await.write(true).await?;
- Ok(member_id)
+ if using_host_mode {
+ if vault.config().vault_admin_list().contains(&member_id) {
+ // Using Host mode authentication, and is indeed an administrator
+ mut_instance.write(true).await?;
+ Ok((member_id, true))
+ } else {
+ // Using Host mode authentication, but not an administrator
+ mut_instance.write(false).await?;
+ Err(TcpTargetError::Authentication(
+ "Authenticate failed.".to_string(),
+ ))
+ }
+ } else {
+ // Not using Host mode authentication
+ mut_instance.write(true).await?;
+ Ok((member_id, false))
+ }
}
}
Err(e) => Err(e),
@@ -108,22 +134,27 @@ pub async fn auth_member(
// Accept Challenge (Local)
if ctx.is_proc_on_local() {
+ let mut mut_instance = instance.lock().await;
let local_workspace = try_get_local_workspace(ctx)?;
+ let (is_host_mode, member_name) = {
+ let cfg = local_workspace.config().lock_owned().await;
+ (cfg.is_host_mode(), cfg.current_account())
+ };
let user_directory = try_get_user_directory(ctx)?;
+ // Inform remote whether to authenticate in Host mode
+ mut_instance.write_msgpack(is_host_mode).await?;
+
// Member name & Private key
- let member_name = local_workspace.config().lock().await.current_account();
let private_key = user_directory.account_private_key_path(&member_name);
- let _ = instance
- .lock()
- .await
+ let _ = mut_instance
.accept_challenge(private_key, &member_name)
.await?;
// Read result
- let challenge_result = instance.lock().await.read::<bool>().await?;
+ let challenge_result = mut_instance.read::<bool>().await?;
if challenge_result {
- return Ok(member_name.clone());
+ return Ok((member_name.clone(), is_host_mode));
} else {
return Err(TcpTargetError::Authentication(
"Authenticate failed.".to_string(),
@@ -136,34 +167,57 @@ pub async fn auth_member(
/// Get the current sheet name based on the context (local or remote).
/// This function handles the communication between local and remote instances
-/// to verify and retrieve the current sheet name.
+/// to verify and retrieve the current sheet name and whether it's a reference sheet.
///
/// On local:
/// - Reads the current sheet from local configuration
/// - Sends the sheet name to remote for verification
-/// - Returns the sheet name if remote confirms it exists
+/// - Returns the sheet name and whether it's a reference sheet if remote confirms it exists
///
/// On remote:
/// - Receives sheet name from local
/// - Verifies the sheet exists in the vault
-/// - Sends confirmation back to local
+/// - Checks if the sheet is a reference sheet
+/// - If allow_ref is true, reference sheets are allowed to pass verification
+/// - Sends confirmation and reference status back to local
///
-/// Returns the verified sheet name or an error if the sheet doesn't exist
+/// Returns a tuple of (SheetName, bool) where the bool indicates if it's a reference sheet,
+/// or an error if the sheet doesn't exist or doesn't meet the verification criteria.
pub async fn get_current_sheet_name(
ctx: &ActionContext,
instance: &Arc<Mutex<ConnectionInstance>>,
member_id: &MemberId,
-) -> Result<SheetName, TcpTargetError> {
+ allow_ref: bool,
+) -> Result<(SheetName, bool), TcpTargetError> {
let mut mut_instance = instance.lock().await;
if ctx.is_proc_on_local() {
+ let workspace = try_get_local_workspace(ctx)?;
let config = LocalConfig::read().await?;
+ let latest = LatestInfo::read_from(LatestInfo::latest_info_path(
+ workspace.local_path(),
+ member_id,
+ ))
+ .await?;
if let Some(sheet_name) = config.sheet_in_use() {
// Send sheet name
mut_instance.write_msgpack(sheet_name).await?;
// Read result
if mut_instance.read_msgpack::<bool>().await? {
- return Ok(sheet_name.clone());
+ // Check if sheet is a reference sheet
+ let is_ref_sheet = latest.reference_sheets.contains(sheet_name);
+ if allow_ref {
+ // Allow reference sheets, directly return the determination result
+ return Ok((sheet_name.clone(), is_ref_sheet));
+ } else if is_ref_sheet {
+ // Not allowed but it's a reference sheet, return an error
+ return Err(TcpTargetError::ReferenceSheetNotAllowed(
+ "Reference sheet not allowed".to_string(),
+ ));
+ } else {
+ // Not allowed but not a reference sheet, return normally
+ return Ok((sheet_name.clone(), false));
+ }
} else {
return Err(TcpTargetError::NotFound("Sheet not found".to_string()));
}
@@ -185,11 +239,27 @@ pub async fn get_current_sheet_name(
// Check if sheet exists
if let Ok(sheet) = vault.sheet(&sheet_name).await
&& let Some(holder) = sheet.holder()
- && holder == member_id
{
- // Tell local the check is passed
- mut_instance.write_msgpack(true).await?;
- return Ok(sheet_name.clone());
+ let is_ref_sheet = holder == VAULT_HOST_NAME;
+ if allow_ref {
+ // Allow reference sheets, directly return the determination result
+ if holder == member_id || holder == VAULT_HOST_NAME {
+ mut_instance.write_msgpack(true).await?;
+ return Ok((sheet.name().clone(), is_ref_sheet));
+ }
+ } else if is_ref_sheet {
+ // Not allowed but it's a reference sheet, return an error
+ mut_instance.write_msgpack(true).await?;
+ return Err(TcpTargetError::ReferenceSheetNotAllowed(
+ "Reference sheet not allowed".to_string(),
+ ));
+ } else {
+ // Not allowed but not a reference sheet, return normally
+ if holder == member_id {
+ mut_instance.write_msgpack(true).await?;
+ return Ok((sheet_name.clone(), false));
+ }
+ }
}
// Tell local the check is not passed
mut_instance.write_msgpack(false).await?;