From a42bbd7ffd94b9f94e761ab5ae371fd8dee44198 Mon Sep 17 00:00:00 2001 From: Kiril Videlov Date: Fri, 9 Feb 2024 17:31:16 +0100 Subject: [PATCH] feat: adds support for omitting host certificate checks when authenticating with ssh --- gitbutler-app/src/gb_repository/repository.rs | 6 +++++ .../src/project_repository/repository.rs | 23 +++++++++++++++---- gitbutler-app/src/projects/project.rs | 2 ++ gitbutler-app/src/projects/storage.rs | 5 ++++ gitbutler-ui/src/lib/backend/projects.ts | 2 ++ .../src/lib/components/PreferencesForm.svelte | 21 ++++++++++++++++- .../routes/[projectId]/settings/+page.svelte | 5 ++-- 7 files changed, 57 insertions(+), 7 deletions(-) diff --git a/gitbutler-app/src/gb_repository/repository.rs b/gitbutler-app/src/gb_repository/repository.rs index 50dd4cd2f..a6eaec590 100644 --- a/gitbutler-app/src/gb_repository/repository.rs +++ b/gitbutler-app/src/gb_repository/repository.rs @@ -143,6 +143,9 @@ impl Repository { }; let mut callbacks = git2::RemoteCallbacks::new(); + if self.project.omit_certificate_check.unwrap_or(false) { + callbacks.certificate_check(|_, _| Ok(git2::CertificateCheckStatus::CertificateOk)); + } callbacks.push_update_reference(move |refname, message| { tracing::debug!( project_id = %self.project.id, @@ -194,6 +197,9 @@ impl Repository { // Set the remote's callbacks let mut callbacks = git2::RemoteCallbacks::new(); + if self.project.omit_certificate_check.unwrap_or(false) { + callbacks.certificate_check(|_, _| Ok(git2::CertificateCheckStatus::CertificateOk)); + } callbacks.push_update_reference(move |refname, message| { tracing::debug!( project_id = %self.project.id, diff --git a/gitbutler-app/src/project_repository/repository.rs b/gitbutler-app/src/project_repository/repository.rs index 86952394f..f0fa3f1ec 100644 --- a/gitbutler-app/src/project_repository/repository.rs +++ b/gitbutler-app/src/project_repository/repository.rs @@ -287,6 +287,9 @@ impl Repository { .ok_or(RemoteError::Auth)?; let mut callbacks = git2::RemoteCallbacks::new(); + if self.project.omit_certificate_check.unwrap_or(false) { + callbacks.certificate_check(|_, _| Ok(git2::CertificateCheckStatus::CertificateOk)); + } let bytes_pushed = Arc::new(AtomicUsize::new(0)); let total_objects = Arc::new(AtomicUsize::new(0)); { @@ -353,12 +356,18 @@ 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")?; + if !self.project.omit_certificate_check.unwrap_or(false) { + ssh::check_known_host(&url).context("failed to check known host")?; + } } for callback in callbacks { + let mut cbs: git2::RemoteCallbacks = callback.into(); + if self.project.omit_certificate_check.unwrap_or(false) { + cbs.certificate_check(|_, _| Ok(git2::CertificateCheckStatus::CertificateOk)); + } match remote.push( &[refspec.as_str()], - Some(&mut git2::PushOptions::new().remote_callbacks(callback.into())), + Some(&mut git2::PushOptions::new().remote_callbacks(cbs)), ) { Ok(()) => { tracing::info!( @@ -395,11 +404,17 @@ impl Repository { 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")?; + if !self.project.omit_certificate_check.unwrap_or(false) { + 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()); + let mut cbs: git2::RemoteCallbacks = callback.into(); + if self.project.omit_certificate_check.unwrap_or(false) { + cbs.certificate_check(|_, _| Ok(git2::CertificateCheckStatus::CertificateOk)); + } + fetch_opts.remote_callbacks(cbs); fetch_opts.prune(git2::FetchPrune::On); match remote.fetch(&[refspec], Some(&mut fetch_opts)) { diff --git a/gitbutler-app/src/projects/project.rs b/gitbutler-app/src/projects/project.rs index 31aacc5c6..e55c23c17 100644 --- a/gitbutler-app/src/projects/project.rs +++ b/gitbutler-app/src/projects/project.rs @@ -76,6 +76,8 @@ pub struct Project { pub gitbutler_code_push_state: Option, #[serde(default)] pub project_data_last_fetch: Option, + #[serde(default)] + pub omit_certificate_check: Option, } impl AsRef for Project { diff --git a/gitbutler-app/src/projects/storage.rs b/gitbutler-app/src/projects/storage.rs index eaff7823e..53f6cc4cc 100644 --- a/gitbutler-app/src/projects/storage.rs +++ b/gitbutler-app/src/projects/storage.rs @@ -46,6 +46,7 @@ pub struct UpdateRequest { pub ok_with_force_push: Option, pub gitbutler_code_push_state: Option, pub project_data_last_fetched: Option, + pub omit_certificate_check: Option, } #[derive(Debug, thiserror::Error)] @@ -130,6 +131,10 @@ impl Storage { *project.ok_with_force_push = ok_with_force_push; } + if let Some(omit_certificate_check) = update_request.omit_certificate_check { + project.omit_certificate_check = Some(omit_certificate_check); + } + self.storage .write(PROJECTS_FILE, &serde_json::to_string_pretty(&projects)?)?; diff --git a/gitbutler-ui/src/lib/backend/projects.ts b/gitbutler-ui/src/lib/backend/projects.ts index 8bac56598..07823827e 100644 --- a/gitbutler-ui/src/lib/backend/projects.ts +++ b/gitbutler-ui/src/lib/backend/projects.ts @@ -32,6 +32,7 @@ export type Project = { api?: CloudProject & { sync: boolean }; preferred_key: Key; ok_with_force_push: boolean; + omit_certificate_check: boolean | undefined; }; export class ProjectService { @@ -70,6 +71,7 @@ export class ProjectService { api?: CloudProject & { sync: boolean }; preferred_key?: Key; okWithForcePush?: boolean; + omitCertificateCheck?: boolean; }) { await invoke('update_project', { project: params }); this.reload(); diff --git a/gitbutler-ui/src/lib/components/PreferencesForm.svelte b/gitbutler-ui/src/lib/components/PreferencesForm.svelte index 6896b3684..88207385e 100644 --- a/gitbutler-ui/src/lib/components/PreferencesForm.svelte +++ b/gitbutler-ui/src/lib/components/PreferencesForm.svelte @@ -7,11 +7,13 @@ export let project: Project; let allowForcePushing = project?.ok_with_force_push; + let omitCertificateCheck = project?.omit_certificate_check; const runCommitHooks = projectRunCommitHooks(project.id); const dispatch = createEventDispatcher<{ updated: { - ok_with_force_push: boolean; + ok_with_force_push?: boolean; + omit_certificate_check?: boolean; }; }>(); @@ -35,6 +37,23 @@ never force push to the trunk.

+
+ { + omitCertificateCheck = !omitCertificateCheck; + dispatch('updated', { omit_certificate_check: omitCertificateCheck }); + }} + /> + + +

+ Enabling this will ignore host certificate checks when authenticating with ssh. +

+
projectService.updateProject({ ...$project$, ...e.detail }); - const onPreferencesUpdated = (e: { detail: { ok_with_force_push: boolean } }) => - projectService.updateProject({ ...$project$, ...e.detail }); + const onPreferencesUpdated = (e: { + detail: { ok_with_force_push?: boolean; omit_certificate_check?: boolean }; + }) => projectService.updateProject({ ...$project$, ...e.detail }); const onDetailsUpdated = async (e: { detail: Project }) => { const api = $user$ && e.detail.api