Compare commits
2
Commits
0c7b1b7706
...
367af4de82
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
367af4de82 | ||
|
|
600f68b63d |
@@ -4476,7 +4476,7 @@ fn latest_release_tag(repo: &str) -> Result<Option<String>> {
|
|||||||
}
|
}
|
||||||
let effective = String::from_utf8_lossy(&output.stdout);
|
let effective = String::from_utf8_lossy(&output.stdout);
|
||||||
let effective = effective.trim();
|
let effective = effective.trim();
|
||||||
Ok(release_tag_from_effective_url(web, &effective))
|
Ok(release_tag_from_effective_url(web, effective))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn release_tag_download_url(repo: &str, tag: &str, artifact: &str) -> Option<String> {
|
fn release_tag_download_url(repo: &str, tag: &str, artifact: &str) -> Option<String> {
|
||||||
@@ -5523,12 +5523,12 @@ fn resolve_forward_agent_endpoint(forward_agent: bool) -> Result<Option<PathBuf>
|
|||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
return match std::env::var_os("SSH_AUTH_SOCK") {
|
match std::env::var_os("SSH_AUTH_SOCK") {
|
||||||
Some(path) if !path.is_empty() => Ok(Some(PathBuf::from(path))),
|
Some(path) if !path.is_empty() => Ok(Some(PathBuf::from(path))),
|
||||||
_ => Err(anyhow!(
|
_ => Err(anyhow!(
|
||||||
"agent forwarding requested but SSH_AUTH_SOCK is not set"
|
"agent forwarding requested but SSH_AUTH_SOCK is not set"
|
||||||
)),
|
)),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -6150,10 +6150,10 @@ fn local_username() -> String {
|
|||||||
local_username_from_env(|name| std::env::var(name).ok())
|
local_username_from_env(|name| std::env::var(name).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_username_from_env(mut get: impl FnMut(&str) -> Option<String>) -> String {
|
fn local_username_from_env(get: impl FnMut(&str) -> Option<String>) -> String {
|
||||||
["USER", "USERNAME"]
|
["USER", "USERNAME"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|name| get(name))
|
.filter_map(get)
|
||||||
.find(|value| !value.is_empty())
|
.find(|value| !value.is_empty())
|
||||||
.unwrap_or_else(|| "unknown".to_string())
|
.unwrap_or_else(|| "unknown".to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-26
@@ -201,7 +201,6 @@ impl DoshClientBuilder {
|
|||||||
match connect_sdk_peer(
|
match connect_sdk_peer(
|
||||||
peer_addr,
|
peer_addr,
|
||||||
&self.client.config,
|
&self.client.config,
|
||||||
&host_config,
|
|
||||||
&self.host,
|
&self.host,
|
||||||
&raw_server,
|
&raw_server,
|
||||||
ssh_port,
|
ssh_port,
|
||||||
@@ -244,7 +243,6 @@ impl ConnectedDoshClient {
|
|||||||
async fn connect_sdk_peer(
|
async fn connect_sdk_peer(
|
||||||
peer_addr: SocketAddr,
|
peer_addr: SocketAddr,
|
||||||
config: &ClientConfig,
|
config: &ClientConfig,
|
||||||
host_config: &HostConfig,
|
|
||||||
host: &str,
|
host: &str,
|
||||||
server: &str,
|
server: &str,
|
||||||
ssh_port: Option<u16>,
|
ssh_port: Option<u16>,
|
||||||
@@ -311,18 +309,17 @@ async fn connect_sdk_peer(
|
|||||||
&hello,
|
&hello,
|
||||||
&server_hello.hello,
|
&server_hello.hello,
|
||||||
)?;
|
)?;
|
||||||
let auth = sign_auth(
|
let auth = sign_auth(NativeAuthSignRequest {
|
||||||
config,
|
config,
|
||||||
host_config,
|
hello: &hello,
|
||||||
&hello,
|
server_hello: &server_hello.hello,
|
||||||
&server_hello.hello,
|
requested_forwardings: requested_forwardings.to_vec(),
|
||||||
requested_forwardings.to_vec(),
|
explicit_identity_files: identity_files.to_vec(),
|
||||||
identity_files.to_vec(),
|
|
||||||
use_ssh_agent,
|
use_ssh_agent,
|
||||||
server,
|
server,
|
||||||
ssh_port,
|
ssh_port,
|
||||||
ssh_config,
|
ssh_config,
|
||||||
)?;
|
})?;
|
||||||
let mut pending_id = [0u8; 16];
|
let mut pending_id = [0u8; 16];
|
||||||
pending_id.copy_from_slice(&server_hello.hello.auth_challenge[..16]);
|
pending_id.copy_from_slice(&server_hello.hello.auth_challenge[..16]);
|
||||||
let auth_packet = protocol::encode_encrypted(
|
let auth_packet = protocol::encode_encrypted(
|
||||||
@@ -387,18 +384,30 @@ fn verify_or_trust_host(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sign_auth(
|
struct NativeAuthSignRequest<'a> {
|
||||||
config: &ClientConfig,
|
config: &'a ClientConfig,
|
||||||
_host_config: &HostConfig,
|
hello: &'a NativeClientHello,
|
||||||
hello: &NativeClientHello,
|
server_hello: &'a native::NativeServerHello,
|
||||||
server_hello: &native::NativeServerHello,
|
|
||||||
requested_forwardings: Vec<ForwardingRequest>,
|
requested_forwardings: Vec<ForwardingRequest>,
|
||||||
explicit_identity_files: Vec<PathBuf>,
|
explicit_identity_files: Vec<PathBuf>,
|
||||||
use_ssh_agent: Option<bool>,
|
use_ssh_agent: Option<bool>,
|
||||||
server: &str,
|
server: &'a str,
|
||||||
ssh_port: Option<u16>,
|
ssh_port: Option<u16>,
|
||||||
ssh_config: &SdkSshConfig,
|
ssh_config: &'a SdkSshConfig,
|
||||||
) -> Result<native::NativeUserAuth> {
|
}
|
||||||
|
|
||||||
|
fn sign_auth(request: NativeAuthSignRequest<'_>) -> Result<native::NativeUserAuth> {
|
||||||
|
let NativeAuthSignRequest {
|
||||||
|
config,
|
||||||
|
hello,
|
||||||
|
server_hello,
|
||||||
|
requested_forwardings,
|
||||||
|
explicit_identity_files,
|
||||||
|
use_ssh_agent,
|
||||||
|
server,
|
||||||
|
ssh_port,
|
||||||
|
ssh_config,
|
||||||
|
} = request;
|
||||||
let use_agent = use_ssh_agent.unwrap_or(config.use_ssh_agent);
|
let use_agent = use_ssh_agent.unwrap_or(config.use_ssh_agent);
|
||||||
let mut errors = Vec::new();
|
let mut errors = Vec::new();
|
||||||
if use_agent && !ssh_config.identities_only {
|
if use_agent && !ssh_config.identities_only {
|
||||||
@@ -448,12 +457,6 @@ fn sdk_identity_paths(
|
|||||||
for path in explicit_identity_files {
|
for path in explicit_identity_files {
|
||||||
push_identity_path(&mut paths, path);
|
push_identity_path(&mut paths, path);
|
||||||
}
|
}
|
||||||
for path in &ssh_config.identity_files {
|
|
||||||
push_identity_path(
|
|
||||||
&mut paths,
|
|
||||||
expand_tilde(&expand_ssh_path_tokens(path, token_context)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if !ssh_config.identities_only {
|
if !ssh_config.identities_only {
|
||||||
for path in &config.identity_files {
|
for path in &config.identity_files {
|
||||||
push_identity_path(
|
push_identity_path(
|
||||||
@@ -462,6 +465,12 @@ fn sdk_identity_paths(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for path in &ssh_config.identity_files {
|
||||||
|
push_identity_path(
|
||||||
|
&mut paths,
|
||||||
|
expand_tilde(&expand_ssh_path_tokens(path, token_context)),
|
||||||
|
);
|
||||||
|
}
|
||||||
paths
|
paths
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -818,10 +827,10 @@ fn local_username() -> Option<String> {
|
|||||||
local_username_from_env(|name| std::env::var(name).ok())
|
local_username_from_env(|name| std::env::var(name).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_username_from_env(mut get: impl FnMut(&str) -> Option<String>) -> Option<String> {
|
fn local_username_from_env(get: impl FnMut(&str) -> Option<String>) -> Option<String> {
|
||||||
["USER", "USERNAME"]
|
["USER", "USERNAME"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|name| get(name))
|
.filter_map(get)
|
||||||
.find(|value| !value.is_empty())
|
.find(|value| !value.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1092,7 +1101,7 @@ mod tests {
|
|||||||
|
|
||||||
let paths = sdk_identity_paths(&config, Vec::new(), &ssh_config, &token_context);
|
let paths = sdk_identity_paths(&config, Vec::new(), &ssh_config, &token_context);
|
||||||
|
|
||||||
assert_eq!(paths, vec![dir.path().join("ssh"), config_identity]);
|
assert_eq!(paths, vec![config_identity, dir.path().join("ssh")]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+43
-9
@@ -578,20 +578,43 @@ mod tests {
|
|||||||
.user("sdk-user")
|
.user("sdk-user")
|
||||||
.service("echo")
|
.service("echo")
|
||||||
.connect();
|
.connect();
|
||||||
let accept = async {
|
let handshake = async {
|
||||||
|
tokio::pin!(connect);
|
||||||
|
let mut connected = None;
|
||||||
|
let mut accepted = None;
|
||||||
loop {
|
loop {
|
||||||
if let DoshServerEvent::Accepted(accepted) = server.recv().await.unwrap() {
|
tokio::select! {
|
||||||
break accepted;
|
result = &mut connect, if connected.is_none() => {
|
||||||
|
connected = Some(result?);
|
||||||
|
}
|
||||||
|
event = server.recv(), if accepted.is_none() => {
|
||||||
|
if let DoshServerEvent::Accepted(connection) = event? {
|
||||||
|
accepted = Some(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if connected.is_some() && accepted.is_some() {
|
||||||
|
return Ok::<_, anyhow::Error>((
|
||||||
|
connected.take().expect("connected result checked"),
|
||||||
|
accepted.take().expect("accepted result checked"),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (connected, accepted) = tokio::join!(connect, accept);
|
let (connected, accepted) = tokio::time::timeout(Duration::from_secs(3), handshake)
|
||||||
let mut client_transport = connected.unwrap().into_transport();
|
.await
|
||||||
|
.expect("SDK client/server authentication timed out")
|
||||||
|
.unwrap();
|
||||||
|
let mut client_transport = connected.into_transport();
|
||||||
let conn_id = accepted.conn_id;
|
let conn_id = accepted.conn_id;
|
||||||
assert_eq!(accepted.services, vec!["echo".to_string()]);
|
assert_eq!(accepted.services, vec!["echo".to_string()]);
|
||||||
|
|
||||||
let stream_id = client_transport.open_service("echo").await.unwrap();
|
let stream_id = client_transport.open_service("echo").await.unwrap();
|
||||||
match server.recv().await.unwrap() {
|
match tokio::time::timeout(Duration::from_secs(3), server.recv())
|
||||||
|
.await
|
||||||
|
.expect("server timed out waiting for stream open")
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
DoshServerEvent::Session {
|
DoshServerEvent::Session {
|
||||||
event: SessionEvent::Stream(TransportEvent::Open(open)),
|
event: SessionEvent::Stream(TransportEvent::Open(open)),
|
||||||
..
|
..
|
||||||
@@ -602,7 +625,10 @@ mod tests {
|
|||||||
other => panic!("unexpected event {other:?}"),
|
other => panic!("unexpected event {other:?}"),
|
||||||
}
|
}
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
client_transport.recv().await.unwrap(),
|
tokio::time::timeout(Duration::from_secs(3), client_transport.recv())
|
||||||
|
.await
|
||||||
|
.expect("client timed out waiting for stream-open acknowledgement")
|
||||||
|
.unwrap(),
|
||||||
SessionEvent::Stream(TransportEvent::OpenOk { .. })
|
SessionEvent::Stream(TransportEvent::OpenOk { .. })
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -611,7 +637,11 @@ mod tests {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
loop {
|
loop {
|
||||||
match server.recv().await.unwrap() {
|
match tokio::time::timeout(Duration::from_secs(3), server.recv())
|
||||||
|
.await
|
||||||
|
.expect("server timed out waiting for stream data")
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
DoshServerEvent::Session {
|
DoshServerEvent::Session {
|
||||||
event: SessionEvent::Stream(TransportEvent::Data(data)),
|
event: SessionEvent::Stream(TransportEvent::Data(data)),
|
||||||
..
|
..
|
||||||
@@ -628,7 +658,11 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
match client_transport.recv().await.unwrap() {
|
match tokio::time::timeout(Duration::from_secs(3), client_transport.recv())
|
||||||
|
.await
|
||||||
|
.expect("client timed out waiting for stream response")
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
SessionEvent::Stream(TransportEvent::Data(data)) => {
|
SessionEvent::Stream(TransportEvent::Data(data)) => {
|
||||||
assert_eq!(data.chunks, vec![b"pong".to_vec()]);
|
assert_eq!(data.chunks, vec![b"pong".to_vec()]);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user