diff --git a/src/backend/database/routes/ssh.ts b/src/backend/database/routes/ssh.ts index fbddf6ad..8c397a6d 100644 --- a/src/backend/database/routes/ssh.ts +++ b/src/backend/database/routes/ssh.ts @@ -1549,6 +1549,29 @@ async function resolveHostCredentials( host: Record, ): Promise> { try { + // Skip credential resolution for shared hosts + // Shared users cannot access the owner's encrypted credentials + if (host.isShared && host.credentialId) { + sshLogger.info( + `Skipping credential resolution for shared host ${host.id} with credentialId ${host.credentialId}`, + { + operation: "resolve_host_credentials_shared", + hostId: host.id as number, + isShared: host.isShared, + }, + ); + // Return host without resolving credentials + // The frontend should handle credential auth for shared hosts differently + const result = { ...host }; + if (host.key_password !== undefined) { + if (result.keyPassword === undefined) { + result.keyPassword = host.key_password; + } + delete result.key_password; + } + return result; + } + if (host.credentialId && host.userId) { const credentialId = host.credentialId as number; const userId = host.userId as string; diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 0b7e7a1d..003a7e12 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -1888,6 +1888,8 @@ "cannotRemoveSystemRole": "Cannot remove system role", "cannotShareWithSelf": "Cannot share host with yourself", "noCustomRolesToAssign": "No custom roles available. System roles are auto-assigned.", + "credentialSharingWarning": "Credential Authentication Not Supported for Sharing", + "credentialSharingWarningDescription": "This host uses credential-based authentication. Shared users will not be able to connect because credentials are encrypted per-user and cannot be shared. Please use password or key-based authentication for hosts you intend to share.", "auditLogs": "Audit Logs", "viewAuditLogs": "View Audit Logs", "action": "Action", diff --git a/src/locales/zh/translation.json b/src/locales/zh/translation.json index 506902aa..f1b966ca 100644 --- a/src/locales/zh/translation.json +++ b/src/locales/zh/translation.json @@ -1749,6 +1749,8 @@ "cannotRemoveSystemRole": "无法移除系统角色", "cannotShareWithSelf": "不能与自己共享主机", "noCustomRolesToAssign": "没有可用的自定义角色。系统角色已自动分配。", + "credentialSharingWarning": "不支持共享使用凭据认证的主机", + "credentialSharingWarningDescription": "此主机使用凭据认证。由于凭据是按用户加密的无法共享,共享用户将无法连接。请为计划共享的主机使用密码或密钥认证。", "auditLogs": "审计日志", "viewAuditLogs": "查看审计日志", "action": "操作", diff --git a/src/ui/desktop/apps/host-manager/HostSharingTab.tsx b/src/ui/desktop/apps/host-manager/HostSharingTab.tsx index ebbf1d59..0375db1a 100644 --- a/src/ui/desktop/apps/host-manager/HostSharingTab.tsx +++ b/src/ui/desktop/apps/host-manager/HostSharingTab.tsx @@ -39,8 +39,10 @@ import { shareHost, getHostAccess, revokeHostAccess, + getSSHHostById, type Role, type AccessRecord, + type SSHHost, } from "@/ui/main-axios.ts"; interface HostSharingTabProps { @@ -79,6 +81,7 @@ export function HostSharingTab({ const [accessList, setAccessList] = React.useState([]); const [loading, setLoading] = React.useState(false); const [currentUserId, setCurrentUserId] = React.useState(""); + const [hostData, setHostData] = React.useState(null); // Load roles const loadRoles = React.useCallback(async () => { @@ -124,13 +127,27 @@ export function HostSharingTab({ } }, [hostId]); + // Load host data + const loadHostData = React.useCallback(async () => { + if (!hostId) return; + + try { + const host = await getSSHHostById(hostId); + setHostData(host); + } catch (error) { + console.error("Failed to load host data:", error); + setHostData(null); + } + }, [hostId]); + React.useEffect(() => { loadRoles(); loadUsers(); if (!isNewHost) { loadAccessList(); + loadHostData(); } - }, [loadRoles, loadUsers, loadAccessList, isNewHost]); + }, [loadRoles, loadUsers, loadAccessList, loadHostData, isNewHost]); // Load current user ID React.useEffect(() => { @@ -235,6 +252,17 @@ export function HostSharingTab({ return (
+ {/* Credential Authentication Warning */} + {hostData?.authType === "Credential" && ( + + + {t("rbac.credentialSharingWarning")} + + {t("rbac.credentialSharingWarningDescription")} + + + )} + {/* Share Form */}