Add WASI SSH CLI and in-process Git SSH transport
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
//! Git exec channels over the shared SSH library, with host-mediated signing.
|
||||
use crate::{Result, repo::error};
|
||||
use gix::bstr::ByteSlice;
|
||||
use std::io;
|
||||
fn parse(input: &str) -> io::Result<gix::Url> {
|
||||
let url = gix::url::parse(input.as_bytes().as_bstr())
|
||||
.map_err(|_| io::Error::other("invalid SSH URL"))?;
|
||||
if url.scheme != gix::url::Scheme::Ssh
|
||||
|| url.host.as_deref().is_none_or(str::is_empty)
|
||||
|| url.password.is_some()
|
||||
|| url.path.is_empty()
|
||||
|| url.path.iter().any(|b| matches!(b, 0 | b'\n' | b'\r'))
|
||||
{
|
||||
return Err(io::Error::other(
|
||||
"use ssh://[user@]host[:port]/path or [user@]host:path without a password",
|
||||
));
|
||||
}
|
||||
Ok(url)
|
||||
}
|
||||
pub fn clean_url(input: &str) -> io::Result<String> {
|
||||
if input.starts_with("http://") || input.starts_with("https://") {
|
||||
crate::http::clean_url(input).map(|url| url.to_string())
|
||||
} else {
|
||||
parse(input)?;
|
||||
Ok(input.into())
|
||||
}
|
||||
}
|
||||
pub fn is_ssh(input: &str) -> bool {
|
||||
!input.starts_with("http://") && !input.starts_with("https://")
|
||||
}
|
||||
pub type Connection =
|
||||
gix_transport::client::git::blocking_io::Connection<sausage_ssh::Reader, sausage_ssh::Writer>;
|
||||
pub fn connection(input: &str, service: gix_transport::Service) -> Result<Connection> {
|
||||
let url = parse(input).map_err(|e| error("SSH URL", e))?;
|
||||
let host = url.host.as_deref().unwrap();
|
||||
let mut session =
|
||||
sausage_ssh::identity::connect(host, url.port.unwrap_or(22), url.user.as_deref(), false)
|
||||
.map_err(|e| error("SSH", e))?;
|
||||
let mut command = service.as_str().as_bytes().to_vec();
|
||||
command.extend_from_slice(b" '");
|
||||
for byte in url.path.iter() {
|
||||
if *byte == b'\'' {
|
||||
command.extend_from_slice(b"'\\''");
|
||||
} else {
|
||||
command.push(*byte);
|
||||
}
|
||||
}
|
||||
command.push(b'\'');
|
||||
session
|
||||
.open_command(&command)
|
||||
.map_err(|e| error("SSH exec", e))?;
|
||||
let (read, write) = session.split();
|
||||
Ok(Connection::new(
|
||||
read,
|
||||
write,
|
||||
gix_transport::Protocol::V1,
|
||||
url.path,
|
||||
None::<(&str, Option<u16>)>,
|
||||
gix_transport::client::git::ConnectMode::Process,
|
||||
false,
|
||||
)
|
||||
.custom_url(Some(input.into())))
|
||||
}
|
||||
Reference in New Issue
Block a user