feat(ssh): support custom SSH agent socket path
This commit is contained in:
parent
c4c427fb67
commit
00541291e3
|
|
@ -155,6 +155,7 @@ function defaultSshTunnel(): SshTunnelConfig {
|
|||
connect_timeout_secs: 5,
|
||||
expose_lan: false,
|
||||
use_ssh_agent: false,
|
||||
ssh_agent_sock_path: "",
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -172,6 +173,7 @@ function normalizeSshTunnel(hop: Partial<SshTunnelConfig>): SshTunnelConfig {
|
|||
connect_timeout_secs: Number(hop.connect_timeout_secs) || 5,
|
||||
expose_lan: !!hop.expose_lan,
|
||||
use_ssh_agent: !!hop.use_ssh_agent,
|
||||
ssh_agent_sock_path: hop.ssh_agent_sock_path || "",
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -248,6 +250,7 @@ function sshLayersForConfig(config: LegacyConnectionConfig): SshTunnelConfig[] {
|
|||
connect_timeout_secs: config.ssh_connect_timeout_secs || 5,
|
||||
expose_lan: config.ssh_expose_lan || false,
|
||||
use_ssh_agent: false,
|
||||
ssh_agent_sock_path: "",
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
|
@ -3477,6 +3480,10 @@ function openExternalUrl(url: string) {
|
|||
<span class="text-xs text-muted-foreground">{{ t("connection.sshUseAgent") }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="selectedSshLayer.use_ssh_agent" class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="text-right text-xs">{{ t("connection.sshAgentSockPath") }}</Label>
|
||||
<Input v-model="selectedSshLayer.ssh_agent_sock_path" class="col-span-3" :placeholder="t('connection.sshAgentSockPathPlaceholder')" :disabled="selectedSshLayer.enabled === false" />
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<span />
|
||||
<label class="col-span-3 flex items-center gap-2 cursor-pointer">
|
||||
|
|
|
|||
|
|
@ -303,6 +303,8 @@ export default {
|
|||
sshHopInvalidPort: "{hop}: SSH port must be between 1 and 65535",
|
||||
sshHopInvalidAuth: "{hop}: password, key path, or ssh-agent is required",
|
||||
sshUseAgent: "Use ssh-agent",
|
||||
sshAgentSockPath: "Agent Socket Path",
|
||||
sshAgentSockPathPlaceholder: "e.g. ~/.ssh/agent.sock",
|
||||
sshHopInvalidTimeout: "{hop}: SSH timeout must be between 1 and 300 seconds",
|
||||
connectTimeout: "Connection Timeout (seconds)",
|
||||
queryTimeout: "Query Timeout (seconds)",
|
||||
|
|
|
|||
|
|
@ -283,6 +283,8 @@ export default {
|
|||
sshHopInvalidPort: "{hop}: el puerto SSH debe estar entre 1 y 65535",
|
||||
sshHopInvalidAuth: "{hop}: se requiere contraseña, ruta de clave o ssh-agent",
|
||||
sshUseAgent: "Usar ssh-agent",
|
||||
sshAgentSockPath: "Ruta del socket del agente",
|
||||
sshAgentSockPathPlaceholder: "ej. ~/.ssh/agent.sock",
|
||||
sshHopInvalidTimeout: "{hop}: el tiempo de espera SSH debe estar entre 1 y 300 segundos",
|
||||
connectTimeout: "Tiempo de espera de conexión (segundos)",
|
||||
queryTimeout: "Tiempo de espera de consulta (segundos)",
|
||||
|
|
|
|||
|
|
@ -288,6 +288,8 @@ export default {
|
|||
sshHopInvalidPort: "{hop}: La porta SSH deve essere compresa tra 1 e 65535",
|
||||
sshHopInvalidAuth: "{hop}: password, percorso chiave o ssh-agent richiesti",
|
||||
sshUseAgent: "Usa ssh-agent",
|
||||
sshAgentSockPath: "Percorso socket agent",
|
||||
sshAgentSockPathPlaceholder: "es. ~/.ssh/agent.sock",
|
||||
sshHopInvalidTimeout: "{hop}: Il timeout SSH deve essere compreso tra 1 e 300 secondi",
|
||||
connectTimeout: "Timeout Connessione (secondi)",
|
||||
queryTimeout: "Timeout Query (secondi)",
|
||||
|
|
|
|||
|
|
@ -302,6 +302,8 @@ export default {
|
|||
sshHopInvalidPort: "{hop}: SSHポートは1〜65535の範囲で指定してください",
|
||||
sshHopInvalidAuth: "{hop}: パスワード、鍵パス、またはssh-agentが必要です",
|
||||
sshUseAgent: "ssh-agentを使用",
|
||||
sshAgentSockPath: "Agentソケットパス",
|
||||
sshAgentSockPathPlaceholder: "例: ~/.ssh/agent.sock",
|
||||
sshHopInvalidTimeout: "{hop}: SSHタイムアウトは1〜300秒の範囲で指定してください",
|
||||
connectTimeout: "接続タイムアウト(秒)",
|
||||
queryTimeout: "クエリタイムアウト(秒)",
|
||||
|
|
|
|||
|
|
@ -288,6 +288,8 @@ export default {
|
|||
sshHopInvalidPort: "{hop}: a porta SSH deve estar entre 1 e 65535",
|
||||
sshHopInvalidAuth: "{hop}: senha, caminho da chave ou ssh-agent é obrigatório",
|
||||
sshUseAgent: "Usar ssh-agent",
|
||||
sshAgentSockPath: "Caminho do socket do agente",
|
||||
sshAgentSockPathPlaceholder: "ex. ~/.ssh/agent.sock",
|
||||
sshHopInvalidTimeout: "{hop}: o timeout SSH deve estar entre 1 e 300 segundos",
|
||||
connectTimeout: "Timeout de Conexão (segundos)",
|
||||
queryTimeout: "Timeout de Consulta (segundos)",
|
||||
|
|
|
|||
|
|
@ -304,6 +304,8 @@ export default {
|
|||
sshHopInvalidPort: "{hop}:SSH 端口必须在 1 到 65535 之间",
|
||||
sshHopInvalidAuth: "{hop}:需要填写密码、密钥路径或勾选使用 ssh-agent",
|
||||
sshUseAgent: "使用 ssh-agent",
|
||||
sshAgentSockPath: "Agent Socket 路径",
|
||||
sshAgentSockPathPlaceholder: "如 ~/.ssh/agent.sock",
|
||||
sshHopInvalidTimeout: "{hop}:SSH 超时时间必须在 1 到 300 秒之间",
|
||||
connectTimeout: "连接超时(秒)",
|
||||
queryTimeout: "查询超时(秒)",
|
||||
|
|
|
|||
|
|
@ -288,6 +288,8 @@ export default {
|
|||
sshHopInvalidPort: "{hop}:SSH 埠必須在 1 到 65535 之間",
|
||||
sshHopInvalidAuth: "{hop}:需要填寫密碼、金鑰路徑或勾選使用 ssh-agent",
|
||||
sshUseAgent: "使用 ssh-agent",
|
||||
sshAgentSockPath: "Agent Socket 路徑",
|
||||
sshAgentSockPathPlaceholder: "如 ~/.ssh/agent.sock",
|
||||
sshHopInvalidTimeout: "{hop}:SSH 逾時時間必須在 1 到 300 秒之間",
|
||||
connectTimeout: "連線逾時(秒)",
|
||||
queryTimeout: "查詢逾時(秒)",
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ export interface SshTunnelConfig {
|
|||
connect_timeout_secs?: number;
|
||||
expose_lan?: boolean;
|
||||
use_ssh_agent?: boolean;
|
||||
ssh_agent_sock_path?: string;
|
||||
}
|
||||
|
||||
export interface ProxyTunnelConfig {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ async fn connect_and_authenticate(
|
|||
ssh_key_path: &str,
|
||||
ssh_key_passphrase: &str,
|
||||
use_ssh_agent: bool,
|
||||
ssh_agent_sock_path: &str,
|
||||
connect_timeout_secs: u64,
|
||||
) -> Result<Handle<SshClient>, String> {
|
||||
let config = Arc::new(ssh_client_config());
|
||||
|
|
@ -108,7 +109,7 @@ async fn connect_and_authenticate(
|
|||
return Err("SSH password authentication failed".to_string());
|
||||
}
|
||||
} else if use_ssh_agent {
|
||||
match try_authenticate_with_agent(&mut session, ssh_user, &connect_timeout).await {
|
||||
match try_authenticate_with_agent(&mut session, ssh_user, ssh_agent_sock_path, &connect_timeout).await {
|
||||
Ok(()) => {}
|
||||
Err(agent_err) => return Err(agent_err),
|
||||
}
|
||||
|
|
@ -124,13 +125,26 @@ async fn connect_and_authenticate(
|
|||
async fn try_authenticate_with_agent(
|
||||
session: &mut Handle<SshClient>,
|
||||
ssh_user: &str,
|
||||
ssh_agent_sock_path: &str,
|
||||
connect_timeout: &Duration,
|
||||
) -> Result<(), String> {
|
||||
#[cfg(unix)]
|
||||
let mut agent = match AgentClient::connect_env().await {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
return Err(format!("No SSH password or key provided, and ssh-agent is unavailable: {e}"));
|
||||
let mut agent = if ssh_agent_sock_path.is_empty() {
|
||||
match AgentClient::connect_env().await {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
return Err(format!("No SSH password or key provided, and ssh-agent is unavailable: {e}"));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match AgentClient::connect_uds(ssh_agent_sock_path).await {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"No SSH password or key provided, and ssh-agent at '{}' is unavailable: {e}",
|
||||
ssh_agent_sock_path
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -430,6 +444,7 @@ async fn tunnel_reconnect_loop(
|
|||
ssh_key_path: String,
|
||||
ssh_key_passphrase: String,
|
||||
use_ssh_agent: bool,
|
||||
ssh_agent_sock_path: String,
|
||||
connect_timeout_secs: u64,
|
||||
listener: TcpListener,
|
||||
remote_host: String,
|
||||
|
|
@ -464,6 +479,7 @@ async fn tunnel_reconnect_loop(
|
|||
&ssh_key_path,
|
||||
&ssh_key_passphrase,
|
||||
use_ssh_agent,
|
||||
&ssh_agent_sock_path,
|
||||
connect_timeout_secs,
|
||||
)
|
||||
.await
|
||||
|
|
@ -533,6 +549,7 @@ impl TunnelManager {
|
|||
ssh_key_path: &str,
|
||||
ssh_key_passphrase: &str,
|
||||
use_ssh_agent: bool,
|
||||
ssh_agent_sock_path: &str,
|
||||
connect_timeout_secs: u64,
|
||||
remote_host: &str,
|
||||
remote_port: u16,
|
||||
|
|
@ -555,6 +572,7 @@ impl TunnelManager {
|
|||
ssh_key_path,
|
||||
ssh_key_passphrase,
|
||||
use_ssh_agent,
|
||||
ssh_agent_sock_path,
|
||||
connect_timeout_secs,
|
||||
remote_host,
|
||||
remote_port,
|
||||
|
|
@ -624,6 +642,7 @@ impl TunnelManager {
|
|||
&hop.key_path,
|
||||
&hop.key_passphrase,
|
||||
hop.use_ssh_agent,
|
||||
&hop.ssh_agent_sock_path,
|
||||
effective_hop_timeout(hop),
|
||||
&target_host,
|
||||
target_port,
|
||||
|
|
@ -671,6 +690,7 @@ async fn spawn_tunnel(
|
|||
ssh_key_path: &str,
|
||||
ssh_key_passphrase: &str,
|
||||
use_ssh_agent: bool,
|
||||
ssh_agent_sock_path: &str,
|
||||
connect_timeout_secs: u64,
|
||||
remote_host: &str,
|
||||
remote_port: u16,
|
||||
|
|
@ -691,6 +711,7 @@ async fn spawn_tunnel(
|
|||
ssh_key_path,
|
||||
ssh_key_passphrase,
|
||||
use_ssh_agent,
|
||||
ssh_agent_sock_path,
|
||||
connect_timeout_secs,
|
||||
)
|
||||
.await?;
|
||||
|
|
@ -704,6 +725,7 @@ async fn spawn_tunnel(
|
|||
ssh_key_path.to_string(),
|
||||
ssh_key_passphrase.to_string(),
|
||||
use_ssh_agent,
|
||||
ssh_agent_sock_path.to_string(),
|
||||
connect_timeout_secs,
|
||||
listener,
|
||||
remote_host.to_string(),
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ pub async fn start_transport_layers(
|
|||
&ssh.key_path,
|
||||
&ssh.key_passphrase,
|
||||
ssh.use_ssh_agent,
|
||||
&ssh.ssh_agent_sock_path,
|
||||
effective_ssh_connect_timeout_secs(ssh.connect_timeout_secs),
|
||||
&target_endpoint.host,
|
||||
target_endpoint.port,
|
||||
|
|
|
|||
|
|
@ -148,6 +148,11 @@ pub struct SshTunnelConfig {
|
|||
pub expose_lan: bool,
|
||||
#[serde(default)]
|
||||
pub use_ssh_agent: bool,
|
||||
/// Custom SSH agent socket path (e.g. `~/.ssh/agent.sock`).
|
||||
/// When set and `use_ssh_agent` is true, this path is used instead of
|
||||
/// the `SSH_AUTH_SOCK` environment variable.
|
||||
#[serde(default)]
|
||||
pub ssh_agent_sock_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ export interface SshTunnelConfig {
|
|||
connect_timeout_secs?: number;
|
||||
expose_lan?: boolean;
|
||||
use_ssh_agent?: boolean;
|
||||
ssh_agent_sock_path?: string;
|
||||
}
|
||||
|
||||
export interface ProxyTunnelConfig {
|
||||
|
|
|
|||
Loading…
Reference in New Issue