diff --git a/app/src/main/java/io/github/wiiznokes/gitnote/data/AppPreferences.kt b/app/src/main/java/io/github/wiiznokes/gitnote/data/AppPreferences.kt index 5747647c..fdd94d0e 100644 --- a/app/src/main/java/io/github/wiiznokes/gitnote/data/AppPreferences.kt +++ b/app/src/main/java/io/github/wiiznokes/gitnote/data/AppPreferences.kt @@ -86,7 +86,6 @@ class AppPreferences( val userPassUsername = stringPreference("userPassUsername", "") val userPassPassword = stringPreference("userPassPassword", "") - val sshUsername = stringPreference("sshUsername", "") val publicKey = stringPreference("publicKey", "") val privateKey = stringPreference("privateKey", "") val passphrase = stringPreference("passphrase", "") @@ -104,7 +103,6 @@ class AppPreferences( } CredType.Ssh -> Cred.Ssh( - username = this.sshUsername.get(), publicKey = this.publicKey.get(), privateKey = this.privateKey.get(), passphrase = this.passphrase.get().ifEmpty { null } @@ -116,7 +114,6 @@ class AppPreferences( when (cred) { is Cred.Ssh -> { credType.update(CredType.Ssh) - sshUsername.update(cred.username) publicKey.update(cred.publicKey) privateKey.update(cred.privateKey) passphrase.update(cred.passphrase ?: "") diff --git a/app/src/main/rust/.gitignore b/app/src/main/rust/.gitignore index a1fb3cb8..00f9c6db 100644 --- a/app/src/main/rust/.gitignore +++ b/app/src/main/rust/.gitignore @@ -1,4 +1,5 @@ target/ /openssl-prebuild/*/install /vendor -/repo_test \ No newline at end of file +/repo_test +/test_clone \ No newline at end of file diff --git a/app/src/main/rust/Cargo.lock b/app/src/main/rust/Cargo.lock index 919bfd65..559443de 100644 --- a/app/src/main/rust/Cargo.lock +++ b/app/src/main/rust/Cargo.lock @@ -24,10 +24,60 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbb4e440d04be07da1f1bf44fb4495ebd58669372fe0cffa6e48595ac5bd88a3" dependencies = [ "android_log-sys", - "env_filter", + "env_filter 0.1.4", "log", ] +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + [[package]] name = "anyhow" version = "1.0.103" @@ -40,6 +90,12 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.13.1" @@ -100,6 +156,12 @@ dependencies = [ "inout", ] +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + [[package]] name = "combine" version = "4.6.7" @@ -155,6 +217,37 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + [[package]] name = "digest" version = "0.10.7" @@ -207,6 +300,35 @@ dependencies = [ "regex", ] +[[package]] +name = "env_filter" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" +dependencies = [ + "anstream", + "anstyle", + "env_filter 2.0.0", + "jiff", + "log", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -266,7 +388,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddddbf932745a6be37109b6112d3ee09696106f848449069d3a57bba937ab82e" dependencies = [ - "bitflags", + "bitflags 2.13.1", "libc", "libgit2-sys", "log", @@ -282,6 +404,7 @@ dependencies = [ "android_logger", "anyhow", "bstr", + "env_logger", "git2", "gix-url", "include-lines", @@ -295,9 +418,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbbecb0f8dc5cdf6cbde69133f7072064dfc9da4cf0046913afb6857b07300fa" +checksum = "1ed3e8d7a82e886e17a72e03d4ba0c13db6f2219b6cd4e2900b4cae426ec20c9" dependencies = [ "bstr", "gix-trace", @@ -307,27 +430,40 @@ dependencies = [ [[package]] name = "gix-trace" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44dc45eae785c0eb14173e0f152e6e224dcf4d45b6a6999a3aed22af541ad678" +checksum = "be3eb81d9dc914335923e50d52829c551feefd6a72d176c4130c546b67a60814" [[package]] name = "gix-url" -version = "0.36.2" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d68e70e96da0e5f9c871f1566349e0fd0e1a20bb483c7f54af1dd0b85b4b29" +checksum = "42d10e53b8eae21ee601687f47bbbd6cb2ed7162cb4c1cafdd422fb7ec64cbee" dependencies = [ "bstr", "gix-path", + "gix-utils", "percent-encoding", "thiserror", ] +[[package]] +name = "gix-utils" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1795bd2a970ca8b2185318c2abb97d955c71992f1cf28de73ad3b593a9f3ce8" +dependencies = [ + "bstr", + "fastrand", + "getrandom 0.4.3", + "unicode-normalization", +] + [[package]] name = "gix-validate" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc6fc771c4063ba7cd2f47b91fb6076251c6a823b64b7fe7b8874b0fe4afae3" +checksum = "9a034e84d1e04e1b1f20f51f12491da230b6ac8b925d0c8e1b89bcd87a7c5ccc" dependencies = [ "bstr", ] @@ -463,6 +599,48 @@ dependencies = [ "generic-array", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "jiff" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668b7183bd07af9a4885f5c35b0cc5c83c4607a913c16b7e17291832910d2dcc" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09" +dependencies = [ + "defmt", +] + +[[package]] +name = "jiff-static" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a69dcb3a21cfb32ce1cd056169337ca284af0766dd766e7878819b251a49204" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "jni" version = "0.22.4" @@ -586,6 +764,12 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + [[package]] name = "openssl-probe" version = "0.1.6" @@ -635,6 +819,21 @@ version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +[[package]] +name = "portable-atomic" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + [[package]] name = "potential_utf" version = "0.1.5" @@ -916,6 +1115,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "typenum" version = "1.20.1" @@ -928,6 +1142,15 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + [[package]] name = "url" version = "2.5.8" @@ -946,6 +1169,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/app/src/main/rust/Cargo.toml b/app/src/main/rust/Cargo.toml index 17b83b6a..e04a2ee6 100644 --- a/app/src/main/rust/Cargo.toml +++ b/app/src/main/rust/Cargo.toml @@ -25,9 +25,12 @@ anyhow = "1" zeroize = "1" libgit2-sys = "0.18" include-lines = "1" -gix-url = "0.36" +gix-url = "0.37" bstr = "1.13" +[dev-dependencies] +env_logger = "0.11" + [profile.release] strip = "symbols" diff --git a/app/src/main/rust/src/lib.rs b/app/src/main/rust/src/lib.rs index 499fada4..9d211d92 100644 --- a/app/src/main/rust/src/lib.rs +++ b/app/src/main/rust/src/lib.rs @@ -6,7 +6,7 @@ use jni::objects::{JClass, JObject, JString, JValue}; use jni::sys::{jboolean, jint}; use jni::{Env, NativeMethod, jni_sig, jni_str, native_method}; -use crate::callback::ProgressCB; +use crate::callback::JniProgressCB; use crate::key_gen::gen_keys; use crate::utils::install_panic_hook; @@ -216,7 +216,6 @@ pub enum Cred { password: String, }, Ssh { - username: String, public_key: String, private_key: String, passphrase: Option, @@ -248,13 +247,11 @@ impl Debug for Cred { .field("username", username) .finish(), Self::Ssh { - username, public_key, private_key: _private_key, passphrase: _passphrase, } => f .debug_struct("Ssh") - .field("username", username) .field("public_key", public_key) .finish(), } @@ -317,14 +314,12 @@ impl Cred { Ok(Some(Cred::UserPassPlainText { username, password })) } "io.github.wiiznokes.gitnote.ui.model.Cred$Ssh" => { - let username = jstring_field!(env, cred_obj, "username"); let public_key = jstring_field!(env, cred_obj, "publicKey"); let private_key = jstring_field!(env, cred_obj, "privateKey"); let passphrase = jstring_field_nullable!(env, cred_obj, "passphrase"); Ok(Some(Cred::Ssh { - username, public_key, private_key, passphrase, @@ -338,19 +333,22 @@ impl Cred { mod callback { use jni::{Env, jni_sig, jni_str, objects::JObject}; - pub struct ProgressCB<'ptr, 'local> { + pub struct JniProgressCB<'ptr, 'local> { env: &'ptr mut Env<'local>, callback_class: JObject<'local>, } - impl<'ptr, 'local> ProgressCB<'ptr, 'local> { + impl<'ptr, 'local> JniProgressCB<'ptr, 'local> { pub fn new(env: &'ptr mut Env<'local>, callback_class: JObject<'local>) -> Self { Self { env, callback_class, } } - pub fn progress(&mut self, progress: i32) -> bool { + } + + impl<'ptr, 'local> ProgressCB for JniProgressCB<'ptr, 'local> { + fn progress(&mut self, progress: i32) -> bool { let res = self .env .call_method( @@ -364,6 +362,20 @@ mod callback { res.z().unwrap() } } + + #[cfg(test)] + pub struct DummyProgressCB; + + #[cfg(test)] + impl ProgressCB for DummyProgressCB { + fn progress(&mut self, _progress: i32) -> bool { + true + } + } + + pub trait ProgressCB { + fn progress(&mut self, progress: i32) -> bool; + } } fn clone_repo_lib<'local>( env: &mut Env<'local>, @@ -384,7 +396,7 @@ fn clone_repo_lib<'local>( } }; - let cb = ProgressCB::new(env, progress_callback); + let cb = JniProgressCB::new(env, progress_callback); unwrap_or_log!( libgit2::clone_repo(&repo_path, &remote_url, cred, cb), diff --git a/app/src/main/rust/src/libgit2/mod.rs b/app/src/main/rust/src/libgit2/mod.rs index a05a45e8..19c3a63c 100644 --- a/app/src/main/rust/src/libgit2/mod.rs +++ b/app/src/main/rust/src/libgit2/mod.rs @@ -11,12 +11,14 @@ use git2::{ Repository, Signature, StatusOptions, TreeWalkMode, TreeWalkResult, }; -use crate::{Cred, Error, GitAuthor, ProgressCB, mime_types::is_extension_supported}; +use crate::{Cred, Error, GitAuthor, callback::ProgressCB, mime_types::is_extension_supported}; mod merge; #[cfg(test)] mod test; +#[cfg(test)] +mod test_clone; #[cfg(test)] mod test_merge; @@ -29,7 +31,10 @@ static REPO: LazyLock>> = LazyLock::new(|| Mutex::new(N static HOME_PATH: OnceLock = OnceLock::new(); fn apply_ssh_workaround(clone: bool) { - let home = HOME_PATH.get().unwrap(); + let Some(home) = HOME_PATH.get() else { + warn!("home path not set"); + return; + }; if clone { unsafe { @@ -127,18 +132,20 @@ fn current_branch(repo: &Repository) -> Result { )) } -fn credential_helper(cred: &Cred) -> Result { +fn credential_helper( + cred: &Cred, + username_from_url: Option<&str>, +) -> Result { match cred { Cred::UserPassPlainText { username, password } => { git2::Cred::userpass_plaintext(username, password) } Cred::Ssh { - username, private_key, public_key, passphrase, } => git2::Cred::ssh_key_from_memory( - username, + username_from_url.unwrap_or("git"), Some(public_key), private_key, passphrase.as_deref(), @@ -150,7 +157,7 @@ pub fn clone_repo( repo_path: &str, remote_url: &str, cred: Option, - mut cb: ProgressCB, + mut cb: impl ProgressCB, ) -> Result<(), Error> { apply_ssh_workaround(true); let mut callbacks = RemoteCallbacks::new(); @@ -158,8 +165,10 @@ pub fn clone_repo( callbacks.certificate_check(|_cert, _| Ok(CertificateCheckStatus::CertificateOk)); if let Some(cred) = cred { - callbacks - .credentials(move |_url, _username_from_url, _allowed_types| credential_helper(&cred)); + callbacks.credentials(move |_url, username_from_url, _allowed_types| { + debug!("allowed_types: {:?}", _allowed_types); + credential_helper(&cred, username_from_url) + }); } callbacks.transfer_progress(|stats: Progress| { @@ -272,8 +281,9 @@ pub fn push(cred: Option) -> Result<(), Error> { callbacks.certificate_check(|_cert, _| Ok(CertificateCheckStatus::CertificateOk)); if let Some(cred) = cred { - callbacks - .credentials(move |_url, _username_from_url, _allowed_types| credential_helper(&cred)); + callbacks.credentials(move |_url, username_from_url, _allowed_types| { + credential_helper(&cred, username_from_url) + }); } let mut push_opts = PushOptions::new(); @@ -301,8 +311,9 @@ pub fn pull(cred: Option, author: &GitAuthor) -> Result<(), Error> { callbacks.certificate_check(|_cert, _| Ok(CertificateCheckStatus::CertificateOk)); if let Some(cred) = cred { - callbacks - .credentials(move |_url, _username_from_url, _allowed_types| credential_helper(&cred)); + callbacks.credentials(move |_url, username_from_url, _allowed_types| { + credential_helper(&cred, username_from_url) + }); } let mut fetch_options = FetchOptions::new(); diff --git a/app/src/main/rust/src/libgit2/test_clone.rs b/app/src/main/rust/src/libgit2/test_clone.rs new file mode 100644 index 00000000..f4a03426 --- /dev/null +++ b/app/src/main/rust/src/libgit2/test_clone.rs @@ -0,0 +1,26 @@ +use std::fs; + +use crate::{callback::DummyProgressCB, libgit2::clone_repo}; + +fn setup_logs() { + env_logger::init(); +} + +#[test] +#[ignore = "local testing"] +fn basic() { + setup_logs(); + + let repo_path = "test_clone/repo1"; + let remote_url = "ssh://name@9.9.9.9:111/name/name.git"; + + let cred = Some(crate::Cred::Ssh { + public_key: String::from(""), + private_key: String::from(""), + passphrase: None, + }); + + let _ = fs::remove_dir_all(repo_path); + + clone_repo(repo_path, remote_url, cred, DummyProgressCB).unwrap(); +}