mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-24 18:12:48 +03:00
fix: ensure known_hosts is up to date
This commit is contained in:
parent
9e57b90f7d
commit
14254fe23c
56
Cargo.lock
generated
56
Cargo.lock
generated
@ -974,7 +974,7 @@ dependencies = [
|
||||
"hashbrown 0.14.0",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
"parking_lot_core 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1805,6 +1805,7 @@ dependencies = [
|
||||
"similar",
|
||||
"slug",
|
||||
"ssh-key",
|
||||
"ssh2",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-context-menu",
|
||||
@ -1911,7 +1912,7 @@ dependencies = [
|
||||
"futures-timer",
|
||||
"no-std-compat",
|
||||
"nonzero_ext",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"quanta",
|
||||
"rand 0.8.5",
|
||||
"smallvec",
|
||||
@ -2975,7 +2976,7 @@ dependencies = [
|
||||
"file-id",
|
||||
"log",
|
||||
"notify",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@ -3293,6 +3294,17 @@ version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
@ -3300,7 +3312,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
"parking_lot_core 0.9.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall 0.2.16",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3749,7 +3775,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93"
|
||||
dependencies = [
|
||||
"log",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"scheduled-thread-pool",
|
||||
]
|
||||
|
||||
@ -4214,7 +4240,7 @@ version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19"
|
||||
dependencies = [
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4767,6 +4793,18 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ssh2"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7fe461910559f6d5604c3731d00d2aafc4a83d1665922e280f42f9a168d5455"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"libssh2-sys",
|
||||
"parking_lot 0.11.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
@ -4796,7 +4834,7 @@ checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
|
||||
dependencies = [
|
||||
"new_debug_unreachable",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"phf_shared 0.10.0",
|
||||
"precomputed-hash",
|
||||
"serde",
|
||||
@ -4937,7 +4975,7 @@ dependencies = [
|
||||
"ndk-sys",
|
||||
"objc",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"png",
|
||||
"raw-window-handle",
|
||||
"scopeguard",
|
||||
@ -5335,7 +5373,7 @@ dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"parking_lot 0.12.1",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2 0.5.5",
|
||||
|
@ -58,6 +58,7 @@ sha2 = "0.10.8"
|
||||
similar = { version = "2.2.1", features = ["unicode"] }
|
||||
slug = "0.1.5"
|
||||
ssh-key = { version = "0.6.3", features = [ "alloc", "ed25519" ] }
|
||||
ssh2 = { version = "0.9.4", features = ["vendored-openssl"] }
|
||||
tauri = { version = "1.5.2", features = ["dialog-open", "fs-read-file", "path-all", "process-relaunch", "protocol-asset", "shell-open", "system-tray", "window-maximize", "window-start-dragging", "window-unmaximize"] }
|
||||
tauri-plugin-context-menu = { git = "https://github.com/gitbutlerapp/tauri-plugin-context-menu", branch = "main" }
|
||||
tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
|
||||
|
@ -18,7 +18,7 @@ pub struct Url {
|
||||
/// The password associated with a user.
|
||||
password: Option<String>,
|
||||
/// The host to which to connect. Localhost is implied if `None`.
|
||||
host: Option<String>,
|
||||
pub host: Option<String>,
|
||||
/// When serializing, use the alternative forms as it was parsed as such.
|
||||
serialize_alternative_form: bool,
|
||||
/// The port to use when connecting to a host. If `None`, standard ports depending on `scheme` will be used.
|
||||
|
@ -22,6 +22,7 @@ pub mod projects;
|
||||
pub mod reader;
|
||||
pub mod sentry;
|
||||
pub mod sessions;
|
||||
pub mod ssh;
|
||||
pub mod storage;
|
||||
pub mod users;
|
||||
pub mod virtual_branches;
|
||||
|
@ -7,7 +7,7 @@ use anyhow::{Context, Result};
|
||||
|
||||
use crate::{
|
||||
git::{self, credentials::HelpError, Url},
|
||||
keys, projects, reader, users,
|
||||
keys, projects, reader, ssh, users,
|
||||
virtual_branches::Branch,
|
||||
};
|
||||
|
||||
@ -352,6 +352,9 @@ impl Repository {
|
||||
|
||||
let auth_flows = credentials.help(self, branch.remote())?;
|
||||
for (mut remote, callbacks) in auth_flows {
|
||||
if let Some(url) = remote.url().context("failed to get remote url")? {
|
||||
ssh::check_known_host(&url).context("failed to check known host")?;
|
||||
}
|
||||
for callback in callbacks {
|
||||
match remote.push(
|
||||
&[refspec.as_str()],
|
||||
@ -391,6 +394,9 @@ impl Repository {
|
||||
let refspec = &format!("+refs/heads/*:refs/remotes/{}/*", remote_name);
|
||||
let auth_flows = credentials.help(self, remote_name)?;
|
||||
for (mut remote, callbacks) in auth_flows {
|
||||
if let Some(url) = remote.url().context("failed to get remote url")? {
|
||||
ssh::check_known_host(&url).context("failed to check known host")?;
|
||||
}
|
||||
for callback in callbacks {
|
||||
let mut fetch_opts = git2::FetchOptions::new();
|
||||
fetch_opts.remote_callbacks(callback.into());
|
||||
|
63
packages/tauri/src/ssh.rs
Normal file
63
packages/tauri/src/ssh.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use std::{env, fs, path::Path};
|
||||
|
||||
use ssh2::{self, CheckResult, KnownHostFileKind};
|
||||
|
||||
use crate::git;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
Ssh(ssh2::Error),
|
||||
#[error(transparent)]
|
||||
Io(std::io::Error),
|
||||
#[error("mismatched host key")]
|
||||
MismatchedHostKey,
|
||||
#[error("failed to check the known hosts")]
|
||||
Failure,
|
||||
}
|
||||
|
||||
pub fn check_known_host(remote_url: &git::Url) -> Result<(), Error> {
|
||||
let host = if let Some(host) = remote_url.host.as_ref() {
|
||||
host
|
||||
} else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let mut session = ssh2::Session::new().map_err(Error::Ssh)?;
|
||||
session
|
||||
.set_tcp_stream(std::net::TcpStream::connect(format!("{}:22", host)).map_err(Error::Io)?);
|
||||
session.handshake().map_err(Error::Ssh)?;
|
||||
|
||||
let mut known_hosts = session.known_hosts().map_err(Error::Ssh)?;
|
||||
|
||||
// Initialize the known hosts with a global known hosts file
|
||||
let dotssh = Path::new(&env::var("HOME").unwrap()).join(".ssh");
|
||||
let file = dotssh.join("known_hosts");
|
||||
if !file.exists() {
|
||||
fs::create_dir_all(&dotssh).map_err(Error::Io)?;
|
||||
fs::File::create(&file).map_err(Error::Io)?;
|
||||
}
|
||||
|
||||
known_hosts
|
||||
.read_file(&file, KnownHostFileKind::OpenSSH)
|
||||
.map_err(Error::Ssh)?;
|
||||
|
||||
// Now check to see if the seesion's host key is anywhere in the known
|
||||
// hosts file
|
||||
let (key, key_type) = session.host_key().unwrap();
|
||||
match known_hosts.check(host, key) {
|
||||
CheckResult::Match => Ok(()),
|
||||
CheckResult::Mismatch => Err(Error::MismatchedHostKey),
|
||||
CheckResult::Failure => Err(Error::Failure),
|
||||
CheckResult::NotFound => {
|
||||
tracing::info!("adding host key for {}", host);
|
||||
known_hosts
|
||||
.add(host, key, "added by gitbutler client", key_type.into())
|
||||
.map_err(Error::Ssh)?;
|
||||
known_hosts
|
||||
.write_file(&file, KnownHostFileKind::OpenSSH)
|
||||
.map_err(Error::Ssh)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user