diff --git a/CHANGELOG.md b/CHANGELOG.md index d2ca7c7..d8c7f87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Released on 20/09/2025 +- [Issue 331](https://github.com/veeso/termscp/issues/331): Added new `import-ssh-hosts` CLI subcommand to import all the hosts from the ssh config as bookmarks. - [Issue 356](https://github.com/veeso/termscp/issues/356): Fixed SSH auth issue not trying with the password if any RSA key was found. - [Issue 334](https://github.com/veeso/termscp/issues/334): SMB support for MacOS with vendored build of libsmbclient. - [Issue 337](https://github.com/veeso/termscp/issues/337): Migrated to libssh.org on Linux and MacOS for better ssh agent support. diff --git a/Cargo.lock b/Cargo.lock index 0d06111..c8e2e4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -43,12 +34,6 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -60,9 +45,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arbitrary" @@ -167,9 +152,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.13.3" +version = "1.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d" dependencies = [ "aws-lc-sys", "zeroize", @@ -177,15 +162,16 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.30.0" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +checksum = "a2b715a6010afb9e457ca2b7c9d2b9c344baa8baed7b38dc476034c171b32575" dependencies = [ "bindgen", "cc", "cmake", "dunce", "fs_extra", + "libloading", ] [[package]] @@ -215,9 +201,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.104.0" +version = "1.106.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c488cd6abb0ec9811c401894191932e941c5f91dc226043edacd0afa1634bc" +checksum = "2c230530df49ed3f2b7b4d9c8613b72a04cdac6452eede16d587fc62addfabac" dependencies = [ "aws-credential-types", "aws-runtime", @@ -249,9 +235,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.83.0" +version = "1.84.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cd43af212d2a1c4dedff6f044d7e1961e5d9e7cfe773d70f31d9842413886" +checksum = "357a841807f6b52cb26123878b3326921e2a25faca412fabdd32bd35b7edd5d3" dependencies = [ "aws-credential-types", "aws-runtime", @@ -271,9 +257,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.84.0" +version = "1.86.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ec4a95bd48e0db7a424356a161f8d87bd6a4f0af37204775f0da03d9e39fc3" +checksum = "9d1cc7fb324aa12eb4404210e6381195c5b5e9d52c2682384f295f38716dd3c7" dependencies = [ "aws-credential-types", "aws-runtime", @@ -293,9 +279,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.85.0" +version = "1.86.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410309ad0df4606bc721aff0d89c3407682845453247213a0ccc5ff8801ee107" +checksum = "e7d835f123f307cafffca7b9027c14979f1d403b417d8541d67cf252e8a21e35" dependencies = [ "aws-credential-types", "aws-runtime", @@ -407,9 +393,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147e8eea63a40315d704b97bf9bc9b8c1402ae94f89d5ad6f7550d963309da1b" +checksum = "734b4282fbb7372923ac339cc2222530f8180d9d4745e582de19a18cee409fd8" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -426,11 +412,11 @@ dependencies = [ "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower 0.5.2", "tracing", ] @@ -465,9 +451,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3946acbe1ead1301ba6862e712c7903ca9bb230bdf1fbd1b5ac54158ef2ab1f" +checksum = "4fa63ad37685ceb7762fa4d73d06f1d5493feb88e3f27259b9ed277f4c01b185" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -553,21 +539,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base16ct" version = "0.1.1" @@ -604,25 +575,22 @@ checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "bindgen" -version = "0.69.5" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ "bitflags 2.9.4", "cexpr", "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", + "itertools", "log", "prettyplease", "proc-macro2", "quote", "regex", - "rustc-hash 1.1.0", + "rustc-hash", "shlex", "syn", - "which", ] [[package]] @@ -694,26 +662,26 @@ dependencies = [ [[package]] name = "bytesize" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3c8f83209414aacf0eeae3cf730b18d6981697fba62f200fcfb92b9f082acba" +checksum = "f5c434ae3cf0089ca203e9019ebe529c47ff45cefe8af7c85ecb734ef541822f" [[package]] name = "bytestring" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" +checksum = "113b4343b5f6617e7ad401ced8de3cc8b012e73a594347c307b90db3e9271289" dependencies = [ "bytes", ] [[package]] name = "camino" -version = "1.1.12" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" +checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -736,7 +704,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -765,9 +733,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.36" +version = "1.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5252b3d2648e5eedbc1a6f501e3c795e07025c1e93bbf8bbdd6eef7f447a6d54" +checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f" dependencies = [ "find-msvc-tools", "jobserver", @@ -798,17 +766,16 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-link 0.1.3", + "windows-link 0.2.0", ] [[package]] @@ -1026,7 +993,7 @@ dependencies = [ "document-features", "mio", "parking_lot", - "rustix 1.0.8", + "rustix 1.1.2", "signal-hook", "signal-hook-mio", "winapi", @@ -1191,9 +1158,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", ] @@ -1305,7 +1272,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.0", + "windows-sys 0.60.2", ] [[package]] @@ -1440,12 +1407,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] @@ -1484,9 +1451,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd99930f64d146689264c637b5af2f0233a933bef0d8570e2526bf9e083192d" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" [[package]] name = "flate2" @@ -1684,16 +1651,10 @@ dependencies = [ "js-sys", "libc", "r-efi", - "wasi 0.14.4+wasi-0.2.4", + "wasi 0.14.7+wasi-0.2.4", "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - [[package]] name = "git2" version = "0.20.2" @@ -1970,7 +1931,7 @@ dependencies = [ "pin-project-lite", "rustls-native-certs 0.7.3", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower-service", ] @@ -2000,11 +1961,11 @@ dependencies = [ "hyper 1.7.0", "hyper-util", "log", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-native-certs 0.8.1", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower-service", "webpki-roots", ] @@ -2037,9 +1998,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64 0.22.1", "bytes", @@ -2053,7 +2014,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -2061,9 +2022,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2071,7 +2032,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.2", + "windows-core 0.57.0", ] [[package]] @@ -2198,9 +2159,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", @@ -2268,17 +2229,6 @@ dependencies = [ "syn", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -2314,15 +2264,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -2350,9 +2291,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.78" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -2397,7 +2338,7 @@ dependencies = [ "log", "openssl", "security-framework 2.11.1", - "security-framework 3.3.0", + "security-framework 3.5.1", "windows-sys 0.60.2", "zeroize", ] @@ -2458,7 +2399,7 @@ dependencies = [ "kube-core", "pem", "rand 0.8.5", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-pemfile 2.2.0", "secrecy", "serde", @@ -2490,9 +2431,9 @@ dependencies = [ [[package]] name = "lazy-regex" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60c7310b93682b36b98fa7ea4de998d3463ccbebd94d935d6b48ba5b6ffa7126" +checksum = "191898e17ddee19e60bccb3945aa02339e81edd4a8c50e21fd4d48cdecda7b29" dependencies = [ "lazy-regex-proc_macros", "once_cell", @@ -2501,9 +2442,9 @@ dependencies = [ [[package]] name = "lazy-regex-proc_macros" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ba01db5ef81e17eb10a5e0f2109d1b3a3e29bac3070fdbd7d156bf7dbd206a1" +checksum = "c35dc8b0da83d1a9507e12122c80dea71a9c7c613014347392483a83ea593e04" dependencies = [ "proc-macro2", "quote", @@ -2517,17 +2458,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" -version = "0.2.175" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libdbus-sys" @@ -2560,14 +2495,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.3", + "windows-targets 0.48.5", ] [[package]] name = "libredox" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags 2.9.4", "libc", @@ -2633,9 +2568,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" @@ -2720,9 +2655,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -2935,15 +2870,6 @@ dependencies = [ "objc2-core-foundation", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -2995,9 +2921,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.5.2+3.5.2" +version = "300.5.3+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d270b79e2926f5150189d475bc7e9d2c69f9c4697b185fa917d5a32b792d21b4" +checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" dependencies = [ "cc", ] @@ -3096,16 +3022,16 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "pavao" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5b84c6ab7b745d233668e868f67dac1f40a8329c0f9d41ac50addf36adb883" +checksum = "f7c62e3a544910e4a9bbb56218bad91593b79a27c676e54a36097200d10d2d6e" dependencies = [ "cfg_aliases", "lazy_static", "libc", "log", "pavao-sys", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -3121,9 +3047,9 @@ dependencies = [ [[package]] name = "pavao-sys" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd4336fa254e9df9f752adc3e2b70f01b4eacfb32f34433bafda3a898056737" +checksum = "a3e72a8efe4193b073995a99981a288cfef121027d12c420c647c2f19d4103d4" dependencies = [ "cc", "libc", @@ -3149,20 +3075,20 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" +checksum = "21e0a3a33733faeaf8651dfee72dd0f388f0c8e5ad496a3478fa5a922f49cfa8" dependencies = [ "memchr", - "thiserror 2.0.16", + "thiserror 2.0.17", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb056d9e8ea77922845ec74a1c4e8fb17e7c218cc4fc11a15c5d25e189aa40bc" +checksum = "bc58706f770acb1dbd0973e6530a3cff4746fb721207feb3a8a6064cd0b6c663" dependencies = [ "pest", "pest_generator", @@ -3170,9 +3096,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e404e638f781eb3202dc82db6760c8ae8a1eeef7fb3fa8264b2ef280504966" +checksum = "6d4f36811dfe07f7b8573462465d5cb8965fffc2e71ae377a33aecf14c2c9a2f" dependencies = [ "pest", "pest_meta", @@ -3183,9 +3109,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd1101f170f5903fde0914f899bb503d9ff5271d7ba76bbb70bea63690cc0d5" +checksum = "42919b05089acbd0a5dcd5405fb304d17d1053847b81163d09c4ad18ce8e8420" dependencies = [ "pest", "sha2", @@ -3337,10 +3263,10 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.1", - "rustls 0.23.31", - "socket2 0.6.0", - "thiserror 2.0.16", + "rustc-hash", + "rustls 0.23.32", + "socket2 0.5.10", + "thiserror 2.0.17", "tokio", "tracing", "web-time", @@ -3357,11 +3283,11 @@ dependencies = [ "lru-slab", "rand 0.9.2", "ring", - "rustc-hash 2.1.1", - "rustls 0.23.31", + "rustc-hash", + "rustls 0.23.32", "rustls-pki-types", "slab", - "thiserror 2.0.16", + "thiserror 2.0.17", "tinyvec", "tracing", "web-time", @@ -3376,16 +3302,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.0", + "socket2 0.5.10", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.52.0", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -3467,7 +3393,7 @@ dependencies = [ "crossterm 0.28.1", "indoc", "instability", - "itertools 0.13.0", + "itertools", "lru", "paste", "strum", @@ -3513,14 +3439,14 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -3530,9 +3456,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -3574,7 +3500,7 @@ dependencies = [ "log", "path-slash", "remotefs", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", ] @@ -3725,14 +3651,14 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.31", + "rustls 0.23.32", "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper 1.0.2", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower 0.5.2", "tower-http 0.6.6", "tower-service", @@ -3795,18 +3721,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2" -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -3832,20 +3746,20 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags 2.9.4", "errno", "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", + "linux-raw-sys 0.11.0", + "windows-sys 0.52.0", ] [[package]] @@ -3862,16 +3776,16 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki 0.103.7", "subtle", "zeroize", ] @@ -3910,7 +3824,7 @@ dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.3.0", + "security-framework 3.5.1", ] [[package]] @@ -3953,9 +3867,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "aws-lc-rs", "ring", @@ -4004,11 +3918,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] @@ -4072,9 +3986,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "3.3.0" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ "bitflags 2.9.4", "core-foundation 0.10.1", @@ -4085,9 +3999,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -4130,19 +4044,21 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" dependencies = [ "serde", + "serde_core", ] [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -4157,10 +4073,19 @@ dependencies = [ ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -4169,23 +4094,24 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_spanned" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -4260,6 +4186,15 @@ dependencies = [ "digest", ] +[[package]] +name = "shellexpand" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1fdf65dd6331831494dd616b30351c38e96e45921a27745cf98490458b90bb" +dependencies = [ + "dirs", +] + [[package]] name = "shlex" version = "1.3.0" @@ -4405,9 +4340,9 @@ dependencies = [ [[package]] name = "ssh2-config" -version = "0.6.0" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68555eda3e0678ceb573e60be349cc7a2df7332dcc6a56791af404a361392186" +checksum = "bc7aae258493fa8ea06796b133b9076f3002c46cd1a4085ddd6df7236fee7034" dependencies = [ "anyhow", "bitflags 2.9.4", @@ -4415,7 +4350,7 @@ dependencies = [ "git2", "glob", "log", - "thiserror 2.0.16", + "thiserror 2.0.17", "wildmatch", ] @@ -4467,16 +4402,16 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "suppaftp" -version = "7.0.3" +version = "7.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3453e9f37ec7f6b5c18e1fbb1aa9900ba6a02fb392bfd2bb4e3f78f893eee1" +checksum = "ba8928c89e226be233f0eb1594e9bd023f72a948dc06581c0d908387f57de1de" dependencies = [ "chrono", "futures-lite", "lazy-regex", "log", "native-tls", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -4568,22 +4503,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9" dependencies = [ "quick-xml 0.37.5", - "thiserror 2.0.16", + "thiserror 2.0.17", "windows 0.61.3", "windows-version", ] [[package]] name = "tempfile" -version = "3.21.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", - "rustix 1.0.8", - "windows-sys 0.60.2", + "rustix 1.1.2", + "windows-sys 0.52.0", ] [[package]] @@ -4632,10 +4567,11 @@ dependencies = [ "self_update", "serde", "serial_test", + "shellexpand", "simplelog", "ssh2-config", "tempfile", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "toml", "tui-realm-stdlib", @@ -4671,11 +4607,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -4691,9 +4627,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -4711,11 +4647,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.43" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", + "itoa", "libc", "num-conv", "num_threads", @@ -4768,28 +4705,25 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "slab", "socket2 0.6.0", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.1", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -4818,11 +4752,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.31", + "rustls 0.23.32", "tokio", ] @@ -4853,12 +4787,12 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.5" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "indexmap", - "serde", + "serde_core", "serde_spanned", "toml_datetime", "toml_parser", @@ -4868,27 +4802,27 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "tower" @@ -5040,7 +4974,7 @@ dependencies = [ "crossterm 0.29.0", "lazy-regex", "ratatui", - "thiserror 2.0.16", + "thiserror 2.0.17", "tuirealm_derive", ] @@ -5075,9 +5009,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -5087,9 +5021,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-linebreak" @@ -5109,7 +5043,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" dependencies = [ - "itertools 0.13.0", + "itertools", "unicode-segmentation", "unicode-width 0.1.14", ] @@ -5245,9 +5179,9 @@ dependencies = [ [[package]] name = "version-compare" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" [[package]] name = "version_check" @@ -5321,9 +5255,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.4+wasi-0.2.4" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] @@ -5336,9 +5279,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", @@ -5349,9 +5292,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", @@ -5363,9 +5306,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.51" +version = "0.4.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" dependencies = [ "cfg-if", "js-sys", @@ -5376,9 +5319,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5386,9 +5329,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", @@ -5399,18 +5342,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.101" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.78" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" dependencies = [ "js-sys", "wasm-bindgen", @@ -5460,9 +5403,9 @@ dependencies = [ [[package]] name = "wildmatch" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ce1ab1f8c62655ebe1350f589c61e505cf94d385bc6a12899442d9081e71fd" +checksum = "2d654e41fe05169e03e27b97e0c23716535da037c1652a31fd99c6b2fad84059" [[package]] name = "winapi" @@ -5482,11 +5425,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.48.0", ] [[package]] @@ -5545,8 +5488,8 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-implement 0.60.1", + "windows-interface 0.59.2", "windows-link 0.1.3", "windows-result 0.3.4", "windows-strings", @@ -5576,9 +5519,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" dependencies = [ "proc-macro2", "quote", @@ -5598,9 +5541,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" dependencies = [ "proc-macro2", "quote", @@ -5689,14 +5632,14 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.4", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" dependencies = [ "windows-link 0.2.0", ] @@ -5734,11 +5677,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" dependencies = [ - "windows-link 0.1.3", + "windows-link 0.2.0", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", @@ -5760,9 +5703,9 @@ dependencies = [ [[package]] name = "windows-version" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e061eb0a22b4a1d778ad70f7575ec7845490abb35b08fa320df7895882cacb" +checksum = "700dad7c058606087f6fdc1f88da5841e06da40334413c6cd4367b25ef26d24e" dependencies = [ "windows-link 0.2.0", ] @@ -5923,9 +5866,9 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.45.1" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" @@ -5935,12 +5878,12 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "xattr" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "rustix 1.0.8", + "rustix 1.1.2", ] [[package]] @@ -5981,18 +5924,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", @@ -6022,9 +5965,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] @@ -6086,7 +6029,7 @@ dependencies = [ "flate2", "indexmap", "memchr", - "thiserror 2.0.16", + "thiserror 2.0.17", "time", "zopfli", ] @@ -6099,7 +6042,7 @@ checksum = "dba6063ff82cdbd9a765add16d369abe81e520f836054e997c2db217ceca40c0" dependencies = [ "base64 0.22.1", "ed25519-dalek", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e66b940..c4f56d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ name = "termscp" readme = "README.md" repository = "https://github.com/veeso/termscp" version = "0.19.0" -rust-version = "1.87.0" +rust-version = "1.88.0" [package.metadata.rpm] package = "termscp" @@ -71,11 +71,12 @@ self_update = { version = "^0.42", default-features = false, features = [ "compression-zip-deflate", ] } serde = { version = "^1", features = ["derive"] } +shellexpand = "3" simplelog = "^0.12" ssh2-config = "^0.6" tempfile = "3" thiserror = "2" -tokio = { version = "1.44", features = ["rt"] } +tokio = { version = "1", features = ["rt"] } toml = "^0.9" tui-realm-stdlib = "3" tuirealm = "3" diff --git a/docs/de/man.md b/docs/de/man.md index 63f96f3..be25040 100644 --- a/docs/de/man.md +++ b/docs/de/man.md @@ -10,6 +10,10 @@ - [Unterbefehle](#unterbefehle) - [Ein Thema importieren](#ein-thema-importieren) - [Neueste Version installieren](#neueste-version-installieren) + - [Unterbefehle](#unterbefehle-1) + - [Ein Theme importieren](#ein-theme-importieren) + - [Neueste Version installieren](#neueste-version-installieren-1) + - [SSH-Hosts importieren](#ssh-hosts-importieren) - [S3-Verbindungsparameter](#s3-verbindungsparameter) - [S3-Anmeldeinformationen 🦊](#s3-anmeldeinformationen-) - [Dateiexplorer 📂](#dateiexplorer-) @@ -29,9 +33,9 @@ - [AWS S3 Adressargument](#aws-s3-adressargument-1) - [SMB Adressargument](#smb-adressargument-1) - [Wie das Passwort bereitgestellt werden kann 🔐](#wie-das-passwort-bereitgestellt-werden-kann--1) - - [Unterbefehle](#unterbefehle-1) + - [Unterbefehle](#unterbefehle-2) - [Ein Thema importieren](#ein-thema-importieren-1) - - [Neueste Version installieren](#neueste-version-installieren-1) + - [Neueste Version installieren](#neueste-version-installieren-2) - [S3-Verbindungsparameter](#s3-verbindungsparameter-1) - [S3-Anmeldeinformationen 🦊](#s3-anmeldeinformationen--1) - [Dateiexplorer 📂](#dateiexplorer--1) @@ -173,6 +177,22 @@ Führen Sie termscp als `termscp theme ` aus Führen Sie termscp als `termscp update` aus +### Unterbefehle + +#### Ein Theme importieren + +Führen Sie termscp mit `termscp theme ` aus. + +#### Neueste Version installieren + +Führen Sie termscp mit `termscp update` aus. + +#### SSH-Hosts importieren + +Führen Sie termscp mit `termscp import-ssh-hosts [ssh-config-datei]` aus. + +Importieren Sie alle Hosts aus der angegebenen SSH-Konfigurationsdatei (wenn keine angegeben ist, wird `~/.ssh/config` verwendet) als Lesezeichen in termscp. Identitätsdateien werden ebenfalls als SSH-Schlüssel in termscp importiert. + --- ## S3-Verbindungsparameter diff --git a/docs/es/man.md b/docs/es/man.md index 4f9bd08..8ce718e 100644 --- a/docs/es/man.md +++ b/docs/es/man.md @@ -8,6 +8,10 @@ - [Argumento de dirección de WebDAV](#argumento-de-dirección-de-webdav) - [Argumento dirección por SMB](#argumento-dirección-por-smb) - [Cómo se puede proporcionar la contraseña 🔐](#cómo-se-puede-proporcionar-la-contraseña-) + - [Subcomandos](#subcomandos) + - [Importar un tema](#importar-un-tema) + - [Instalar la versión más reciente](#instalar-la-versión-más-reciente) + - [Importar hosts SSH](#importar-hosts-ssh) - [S3 parámetros de conexión](#s3-parámetros-de-conexión) - [Credenciales de S3 🦊](#credenciales-de-s3-) - [Explorador de archivos 📂](#explorador-de-archivos-) @@ -153,6 +157,22 @@ La contraseña se puede proporcionar básicamente a través de 3 formas cuando s - Con `sshpass`: puede proporcionar la contraseña a través de `sshpass`, p. ej. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - Se te pedirá que ingreses: si no utilizas ninguno de los métodos anteriores, se te pedirá la contraseña, como ocurre con las herramientas más clásicas como `scp`, `ssh`, etc. +### Subcomandos + +#### Importar un tema + +Ejecute termscp como `termscp theme ` + +#### Instalar la versión más reciente + +Ejecute termscp como `termscp update` + +#### Importar hosts SSH + +Ejecute termscp como `termscp import-ssh-hosts [archivo-config-ssh]` + +Importa todos los hosts del archivo de configuración SSH especificado (si no se proporciona, se usará `~/.ssh/config`) como marcadores en termscp. Los archivos de identidad también se importarán como claves SSH en termscp. + --- ## S3 parámetros de conexión diff --git a/docs/fr/man.md b/docs/fr/man.md index 30f5444..d3c177a 100644 --- a/docs/fr/man.md +++ b/docs/fr/man.md @@ -8,6 +8,10 @@ - [Argument d'adresse WebDAV](#argument-dadresse-webdav) - [Argument d'adresse SMB](#argument-dadresse-smb) - [Comment le mot de passe peut être fourni 🔐](#comment-le-mot-de-passe-peut-être-fourni-) + - [Sous-commandes](#sous-commandes) + - [Importer un thème](#importer-un-thème) + - [Installer la dernière version](#installer-la-dernière-version) + - [Importer des hôtes SSH](#importer-des-hôtes-ssh) - [S3 paramètres de connexion](#s3-paramètres-de-connexion) - [Identifiants S3 🦊](#identifiants-s3-) - [Explorateur de fichiers 📂](#explorateur-de-fichiers-) @@ -142,7 +146,6 @@ syntaxe **Other systems**: smb://[username@][:port]/[/path/.../] ``` - #### Comment le mot de passe peut être fourni 🔐 Vous avez probablement remarqué que, lorsque vous fournissez l'adresse comme argument, il n'y a aucun moyen de fournir le mot de passe. @@ -152,6 +155,22 @@ Le mot de passe peut être fourni de 3 manières lorsque l'argument d'adresse es - Avec `sshpass`: vous pouvez fournir un mot de passe via `sshpass`, par ex. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - Il vous sera demandé : si vous n'utilisez aucune des méthodes précédentes, le mot de passe vous sera demandé, comme c'est le cas avec les outils plus classiques tels que `scp`, `ssh`, etc. +### Sous-commandes + +#### Importer un thème + +Exécutez termscp avec `termscp theme ` + +#### Installer la dernière version + +Exécutez termscp avec `termscp update` + +#### Importer des hôtes SSH + +Exécutez termscp avec `termscp import-ssh-hosts [fichier-config-ssh]` + +Importez tous les hôtes du fichier de configuration SSH spécifié (si non fourni, `~/.ssh/config` sera utilisé) comme favoris dans termscp. Les fichiers d'identité seront également importés comme clés SSH dans termscp. + --- ## S3 paramètres de connexion diff --git a/docs/it/man.md b/docs/it/man.md index 7d4effa..d583026 100644 --- a/docs/it/man.md +++ b/docs/it/man.md @@ -8,6 +8,10 @@ - [Argomento indirizzo per WebDAV](#argomento-indirizzo-per-webdav) - [Indirizzo SMB](#indirizzo-smb) - [Come fornire la password 🔐](#come-fornire-la-password-) + - [Sottocomandi](#sottocomandi) + - [Importare un tema](#importare-un-tema) + - [Installare l’ultima versione](#installare-lultima-versione) + - [Importare host SSH](#importare-host-ssh) - [Parametri di connessione S3](#parametri-di-connessione-s3) - [Credenziali S3 🦊](#credenziali-s3-) - [File explorer 📂](#file-explorer-) @@ -140,7 +144,6 @@ SMB ha una sintassi differente rispetto agli altri protocolli e cambia in base a smb://[username@][:port]/[/path/.../] ``` - #### Come fornire la password 🔐 Quando si usa l'argomento indirizzo non è possibile fornire la password direttamente nell'argomento, esistono però altri metodi per farlo: @@ -149,6 +152,22 @@ Quando si usa l'argomento indirizzo non è possibile fornire la password diretta - Tramite `sshpass`: puoi fornire la password tramite l'applicazione GNU/Linux sshpass `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - Forniscila quando richiesta: se non la fornisci tramite nessun metodo precedente, alla connessione ti verrà richiesto di fornirla in un prompt che la oscurerà (come avviene con sudo tipo). +### Sottocomandi + +#### Importare un tema + +Esegui termscp come `termscp theme ` + +#### Installare l’ultima versione + +Esegui termscp come `termscp update` + +#### Importare host SSH + +Esegui termscp come `termscp import-ssh-hosts [file-config-ssh]` + +Importa tutti gli host dal file di configurazione SSH specificato (se non fornito, verrà usato `~/.ssh/config`) come segnalibri in termscp. I file di identità verranno importati come chiavi SSH in termscp. + --- ## Parametri di connessione S3 diff --git a/docs/man.md b/docs/man.md index 15db697..178ddae 100644 --- a/docs/man.md +++ b/docs/man.md @@ -11,6 +11,7 @@ - [Subcommands](#subcommands) - [Import a theme](#import-a-theme) - [Install latest version](#install-latest-version) + - [Import ssh hosts](#import-ssh-hosts) - [S3 connection parameters](#s3-connection-parameters) - [S3 credentials 🦊](#s3-credentials-) - [File explorer 📂](#file-explorer-) @@ -166,6 +167,12 @@ Run termscp as `termscp theme ` Run termscp as `termscp update` +#### Import ssh hosts + +Run termscp as `termscp import-ssh-hosts [ssh-config-file]` + +Import all the hosts from the specified ssh config file (if not provided, `~/.ssh/config` will be used) as bookmarks in termscp. Identity files will be imported as ssh keys in termscp too. + --- ## S3 connection parameters diff --git a/docs/pt-BR/man.md b/docs/pt-BR/man.md index 7d29a09..2fa2d34 100644 --- a/docs/pt-BR/man.md +++ b/docs/pt-BR/man.md @@ -11,6 +11,7 @@ - [Subcomandos](#subcomandos) - [Importar um Tema](#importar-um-tema) - [Instalar a Última Versão](#instalar-a-última-versão) + - [Importar hosts SSH](#importar-hosts-ssh) - [Parâmetros de Conexão do S3](#parâmetros-de-conexão-do-s3) - [Credenciais do S3 🦊](#credenciais-do-s3-) - [Explorador de Arquivos 📂](#explorador-de-arquivos-) @@ -164,6 +165,12 @@ Execute o termscp como `termscp theme ` Execute o termscp como `termscp update` +#### Importar hosts SSH + +Execute o termscp como `termscp import-ssh-hosts [arquivo-config-ssh]` + +Importe todos os hosts do arquivo de configuração SSH especificado (se não for fornecido, `~/.ssh/config` será usado) como favoritos no termscp. Os arquivos de identidade também serão importados como chaves SSH no termscp. + --- ## Parâmetros de Conexão do S3 diff --git a/docs/zh-CN/man.md b/docs/zh-CN/man.md index 7e46c63..a04fc62 100644 --- a/docs/zh-CN/man.md +++ b/docs/zh-CN/man.md @@ -8,6 +8,10 @@ - [WebDAV 地址参数](#webdav-地址参数) - [SMB 地址参数](#smb-地址参数) - [如何输入密码](#如何输入密码) + - [子命令](#子命令) + - [导入主题](#导入主题) + - [安装最新版本](#安装最新版本) + - [导入 SSH 主机](#导入-ssh-主机) - [S3 连接参数](#s3-连接参数) - [Aws S3 凭证](#aws-s3-凭证) - [文件浏览](#文件浏览) @@ -149,6 +153,21 @@ smb://[username@][:port]/[/path/.../] - 通过 `sshpass`: 你可以通过 `sshpass` 传入密码, 例如: `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31` - 提示输入密码:如果你不使用前面的任何方法,你会被提示输入密码,就像 `scp`、`ssh` 等比较经典的工具上一样。 +### 子命令 + +#### 导入主题 + +以 termscp theme 的方式运行 termscp。 + +#### 安装最新版本 + +以 termscp update 的方式运行 termscp。 + +#### 导入 SSH 主机 + +以 `termscp import-ssh-hosts [ssh-config-file]` 的方式运行 termscp。 +从指定的 SSH 配置文件中导入所有主机(如果未提供,则使用 `~/.ssh/config`)作为 termscp 中的书签。身份文件也会作为 SSH 密钥导入到 termscp 中。 + --- ## S3 连接参数 diff --git a/src/activity_manager.rs b/src/activity_manager.rs index faf617c..38ed111 100644 --- a/src/activity_manager.rs +++ b/src/activity_manager.rs @@ -448,35 +448,7 @@ impl ActivityManager { // -- misc fn init_bookmarks_client(keyring: bool) -> Result, String> { - // Get config dir - match environment::init_config_dir() { - Ok(path) => { - // If some configure client, otherwise do nothing; don't bother users telling them that bookmarks are not supported on their system. - if let Some(config_dir_path) = path { - let bookmarks_file: PathBuf = - environment::get_bookmarks_paths(config_dir_path.as_path()); - // Initialize client - BookmarksClient::new( - bookmarks_file.as_path(), - config_dir_path.as_path(), - 16, - keyring, - ) - .map(Option::Some) - .map_err(|e| { - format!( - "Could not initialize bookmarks (at \"{}\", \"{}\"): {}", - bookmarks_file.display(), - config_dir_path.display(), - e - ) - }) - } else { - Ok(None) - } - } - Err(err) => Err(err), - } + crate::support::bookmarks_client(keyring) } /// Initialize configuration client diff --git a/src/cli.rs b/src/cli.rs index 840a18b..e497f89 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -15,6 +15,9 @@ use crate::system::logging::LogLevel; pub enum Task { Activity(NextActivity), + /// Import ssh hosts from the specified ssh config file, or from the default location + /// and save them as bookmarks. + ImportSshHosts(Option), ImportTheme(PathBuf), InstallUpdate, Version, @@ -72,7 +75,8 @@ pub struct Args { #[argh(subcommand)] pub enum ArgsSubcommands { Config(ConfigArgs), - LoadTheme(LoadThemeArgs), + ImportSshHosts(ImportSshHostsArgs), + ImportTheme(ImportThemeArgs), Update(UpdateArgs), } @@ -86,10 +90,20 @@ pub struct ConfigArgs {} #[argh(subcommand, name = "update")] pub struct UpdateArgs {} +#[derive(FromArgs)] +/// import ssh hosts from the specified ssh config file, or from the default location +/// and save them as bookmarks. +#[argh(subcommand, name = "import-ssh-hosts")] +pub struct ImportSshHostsArgs { + #[argh(positional)] + /// optional ssh config file; if not specified, the default location will be used + pub ssh_config: Option, +} + #[derive(FromArgs)] /// import the specified theme #[argh(subcommand, name = "theme")] -pub struct LoadThemeArgs { +pub struct ImportThemeArgs { #[argh(positional)] /// theme file pub theme: PathBuf, @@ -118,6 +132,14 @@ impl RunOpts { } } + pub fn import_ssh_hosts(ssh_config: Option, keyring: bool) -> Self { + Self { + task: Task::ImportSshHosts(ssh_config), + keyring, + ..Default::default() + } + } + pub fn import_theme(theme: PathBuf) -> Self { Self { task: Task::ImportTheme(theme), diff --git a/src/explorer/builder.rs b/src/explorer/builder.rs index d571d80..59a3e89 100644 --- a/src/explorer/builder.rs +++ b/src/explorer/builder.rs @@ -65,10 +65,10 @@ impl FileExplorerBuilder { /// Set formatter for FileExplorer pub fn with_formatter(&mut self, fmt_str: Option<&str>) -> &mut FileExplorerBuilder { - if let Some(e) = self.explorer.as_mut() { - if let Some(fmt_str) = fmt_str { - e.fmt = Formatter::new(fmt_str); - } + if let Some(e) = self.explorer.as_mut() + && let Some(fmt_str) = fmt_str + { + e.fmt = Formatter::new(fmt_str); } self } diff --git a/src/filetransfer/remotefs_builder.rs b/src/filetransfer/remotefs_builder.rs index b52fb7c..5c58fbc 100644 --- a/src/filetransfer/remotefs_builder.rs +++ b/src/filetransfer/remotefs_builder.rs @@ -245,10 +245,10 @@ impl RemoteFsBuilder { } // For SSH protocols, only set password if explicitly provided and non-empty. // This allows the SSH library to prioritize key-based and agent authentication. - if let Some(password) = params.password { - if !password.is_empty() { - opts = opts.password(password); - } + if let Some(password) = params.password + && !password.is_empty() + { + opts = opts.password(password); } if let Some(config_path) = config_client.get_ssh_config() { opts = opts.config_file( diff --git a/src/main.rs b/src/main.rs index 77c08f8..1bff2ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,7 @@ extern crate log; extern crate magic_crypt; use std::env; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::time::Duration; use self::activity_manager::{ActivityManager, NextActivity}; @@ -72,7 +72,10 @@ fn main() -> MainResult<()> { fn parse_args(args: Args) -> Result { let run_opts = match args.nested { Some(ArgsSubcommands::Update(_)) => RunOpts::update(), - Some(ArgsSubcommands::LoadTheme(args)) => RunOpts::import_theme(args.theme), + Some(ArgsSubcommands::ImportSshHosts(subargs)) => { + RunOpts::import_ssh_hosts(subargs.ssh_config, !args.wno_keyring) + } + Some(ArgsSubcommands::ImportTheme(args)) => RunOpts::import_theme(args.theme), Some(ArgsSubcommands::Config(_)) => RunOpts::config(), None => { let mut run_opts: RunOpts = RunOpts::default(); @@ -111,10 +114,10 @@ fn parse_args(args: Args) -> Result { }; // Local directory - if let Some(localdir) = run_opts.remote.local_dir.as_deref() { - if let Err(err) = env::set_current_dir(localdir) { - return Err(format!("Bad working directory argument: {err}")); - } + if let Some(localdir) = run_opts.remote.local_dir.as_deref() + && let Err(err) = env::set_current_dir(localdir) + { + return Err(format!("Bad working directory argument: {err}")); } run_opts @@ -127,6 +130,7 @@ fn parse_args(args: Args) -> Result { /// Run task and return rc fn run(run_opts: RunOpts) -> MainResult<()> { match run_opts.task { + Task::ImportSshHosts(ssh_config) => run_import_ssh_hosts(ssh_config, run_opts.keyring), Task::ImportTheme(theme) => run_import_theme(&theme), Task::InstallUpdate => run_install_update(), Task::Activity(activity) => { @@ -145,6 +149,17 @@ fn print_version() -> MainResult<()> { Ok(()) } +fn run_import_ssh_hosts(ssh_config_path: Option, keyring: bool) -> MainResult<()> { + support::import_ssh_hosts(ssh_config_path, keyring) + .map(|_| { + println!("SSH hosts have been successfully imported!"); + }) + .map_err(|err| { + eprintln!("{err}"); + err.into() + }) +} + fn run_import_theme(theme: &Path) -> MainResult<()> { match support::import_theme(theme) { Ok(_) => { diff --git a/src/support.rs b/src/support.rs index 64a0561..7e083ef 100644 --- a/src/support.rs +++ b/src/support.rs @@ -2,11 +2,14 @@ //! //! this module exposes some extra run modes for termscp, meant to be used for "support", such as installing themes -// mod +mod import_ssh_hosts; + use std::fs; use std::path::{Path, PathBuf}; +pub use self::import_ssh_hosts::import_ssh_hosts; use crate::system::auto_update::{Update, UpdateStatus}; +use crate::system::bookmarks_client::BookmarksClient; use crate::system::config_client::ConfigClient; use crate::system::environment; use crate::system::notifications::Notification; @@ -83,3 +86,36 @@ fn get_config_client() -> Option { } } } + +/// Init [`BookmarksClient`]. +pub fn bookmarks_client(keyring: bool) -> Result, String> { + // Get config dir + match environment::init_config_dir() { + Ok(path) => { + // If some configure client, otherwise do nothing; don't bother users telling them that bookmarks are not supported on their system. + if let Some(config_dir_path) = path { + let bookmarks_file: PathBuf = + environment::get_bookmarks_paths(config_dir_path.as_path()); + // Initialize client + BookmarksClient::new( + bookmarks_file.as_path(), + config_dir_path.as_path(), + 16, + keyring, + ) + .map(Option::Some) + .map_err(|e| { + format!( + "Could not initialize bookmarks (at \"{}\", \"{}\"): {}", + bookmarks_file.display(), + config_dir_path.display(), + e + ) + }) + } else { + Ok(None) + } + } + Err(err) => Err(err), + } +} diff --git a/src/support/import_ssh_hosts.rs b/src/support/import_ssh_hosts.rs new file mode 100644 index 0000000..9e8ae9b --- /dev/null +++ b/src/support/import_ssh_hosts.rs @@ -0,0 +1,326 @@ +use std::fs::File; +use std::io::BufReader; +use std::path::PathBuf; + +use ssh2_config::{Host, HostClause, ParseRule, SshConfig}; + +use crate::filetransfer::params::GenericProtocolParams; +use crate::filetransfer::{FileTransferParams, FileTransferProtocol, ProtocolParams}; + +/// Parameters required to add an ssh key for a host. +struct SshKeyParams { + host: String, + ssh_key: String, + username: String, +} + +/// Import ssh hosts from the specified ssh config file, or from the default location +/// and save them as bookmarks. +pub fn import_ssh_hosts(ssh_config: Option, keyring: bool) -> Result<(), String> { + // get config client + let mut cfg_client = super::get_config_client() + .ok_or_else(|| String::from("Could not import ssh hosts: could not load configuration"))?; + + // resolve ssh_config + let ssh_config = ssh_config.or_else(|| cfg_client.get_ssh_config().map(PathBuf::from)); + + // load bookmarks client + let mut bookmarks_client = super::bookmarks_client(keyring)? + .ok_or_else(|| String::from("Could not import ssh hosts: could not load bookmarks"))?; + + // load ssh config + let ssh_config = match ssh_config { + Some(p) => { + debug!("Importing ssh hosts from file: {}", p.display()); + let mut reader = BufReader::new( + File::open(&p) + .map_err(|e| format!("Could not open ssh config file {}: {e}", p.display()))?, + ); + SshConfig::default().parse(&mut reader, ParseRule::ALLOW_UNKNOWN_FIELDS) + } + None => { + debug!("Importing ssh hosts from default location"); + SshConfig::parse_default_file(ParseRule::ALLOW_UNKNOWN_FIELDS) + } + } + .map_err(|e| format!("Could not parse ssh config file: {e}"))?; + + // iter hosts and add bookmarks + ssh_config + .get_hosts() + .iter() + .flat_map(host_to_params) + .for_each(|(name, params, identity_file_params)| { + debug!("Adding bookmark for host: {name} with params: {params:?}"); + bookmarks_client.add_bookmark(name, params, false); + + // add ssh key if any + if let Some(identity_file_params) = identity_file_params { + debug!( + "Host {host} has identity file, will add ssh key for it", + host = identity_file_params.host + ); + if let Err(err) = cfg_client.add_ssh_key( + &identity_file_params.host, + &identity_file_params.username, + &identity_file_params.ssh_key, + ) { + error!( + "Could not add ssh key for host {host}: {err}", + host = identity_file_params.host + ); + } + } + }); + + // save bookmarks + if let Err(err) = bookmarks_client.write_bookmarks() { + return Err(format!( + "Could not save imported ssh hosts as bookmarks: {err}" + )); + } + + println!("Imported ssh hosts"); + + Ok(()) +} + +/// Tries to derive [`FileTransferParams`] from the specified ssh host. +fn host_to_params( + host: &Host, +) -> impl Iterator)> { + host.pattern + .iter() + .filter_map(|pattern| host_pattern_to_params(host, pattern)) +} + +/// Tries to derive [`FileTransferParams`] from the specified ssh host and pattern. +/// +/// If `IdentityFile` is specified in the host parameters, it will be included in the returned tuple. +fn host_pattern_to_params( + host: &Host, + pattern: &HostClause, +) -> Option<(String, FileTransferParams, Option)> { + debug!("Processing host with pattern: {pattern:?}",); + if pattern.negated || pattern.pattern.contains('*') || pattern.pattern.contains('?') { + debug!("Skipping host with pattern: {pattern}",); + return None; + } + + let address = host + .params + .host_name + .as_deref() + .unwrap_or(pattern.pattern.as_str()) + .to_string(); + debug!("Resolved address for pattern {pattern}: {address}"); + let port = host.params.port.unwrap_or(22); + debug!("Resolved port for pattern {pattern}: {port}"); + let username = host.params.user.clone(); + debug!("Resolved username for pattern {pattern}: {username:?}"); + + let identity_file_params = resolve_identity_file_path(host, pattern, &address); + + Some(( + pattern.to_string(), + FileTransferParams::new( + FileTransferProtocol::Sftp, + ProtocolParams::Generic( + GenericProtocolParams::default() + .address(address) + .port(port) + .username(username), + ), + ), + identity_file_params, + )) +} + +fn resolve_identity_file_path( + host: &Host, + pattern: &HostClause, + resolved_address: &str, +) -> Option { + let (Some(username), Some(identity_file)) = ( + host.params.user.as_ref(), + host.params.identity_file.as_ref().and_then(|v| v.first()), + ) else { + debug!( + "No identity file specified for host {host}, skipping ssh key import", + host = pattern.pattern + ); + return None; + }; + + // expand tilde + let identity_filepath = shellexpand::tilde(&identity_file.display().to_string()).to_string(); + debug!("Resolved identity file for pattern {pattern}: {identity_filepath}",); + let Ok(mut ssh_file) = File::open(identity_file) else { + error!( + "Could not open identity file {identity_filepath} for host {host}", + host = pattern.pattern + ); + return None; + }; + let mut ssh_key = String::new(); + use std::io::Read as _; + if let Err(err) = ssh_file.read_to_string(&mut ssh_key) { + error!( + "Could not read identity file {identity_filepath} for host {host}: {err}", + host = pattern.pattern + ); + return None; + } + + Some(SshKeyParams { + host: resolved_address.to_string(), + username: username.clone(), + ssh_key, + }) +} + +#[cfg(test)] +mod tests { + + use pretty_assertions::assert_eq; + use tempfile::NamedTempFile; + + use super::*; + use crate::system::bookmarks_client::BookmarksClient; + + #[test] + fn test_should_import_ssh_hosts() { + let ssh_test_config = ssh_test_config(); + + // import ssh hosts + let result = import_ssh_hosts(Some(ssh_test_config.config.path().to_path_buf()), false); + assert!(result.is_ok()); + + // verify imported hosts + let config_client = super::super::get_config_client() + .ok_or_else(|| String::from("Could not import ssh hosts: could not load configuration")) + .expect("failed to load config client"); + + // load bookmarks client + let bookmarks_client = super::super::bookmarks_client(false) + .expect("failed to load bookmarks client") + .expect("bookmarks client is none"); + + // verify bookmarks + check_bookmark(&bookmarks_client, "test1", "test1.example.com", 2200, None); + check_bookmark( + &bookmarks_client, + "test2", + "test2.example.com", + 22, + Some("test2user"), + ); + check_bookmark( + &bookmarks_client, + "test3", + "test3.example.com", + 2222, + Some("test3user"), + ); + + // verify ssh keys + let (host, username, _key) = config_client + .get_ssh_key("test3user@test3.example.com") + .expect("ssh key is missing for test3user@test3.example.com"); + + assert_eq!(host, "test3.example.com"); + assert_eq!(username, "test3user"); + } + + fn check_bookmark( + bookmarks_client: &BookmarksClient, + name: &str, + expected_address: &str, + expected_port: u16, + expected_username: Option<&str>, + ) { + // verify bookmarks + let bookmark = bookmarks_client + .get_bookmark(name) + .expect("failed to get bookmark"); + let params1 = bookmark + .params + .generic_params() + .expect("should have generic params"); + assert_eq!(params1.address, expected_address); + assert_eq!(params1.port, expected_port); + assert_eq!(params1.username.as_deref(), expected_username); + assert!(params1.password.is_none()); + } + + struct SshTestConfig { + config: NamedTempFile, + #[allow(dead_code)] + identity_file: NamedTempFile, + } + + fn ssh_test_config() -> SshTestConfig { + use std::io::Write as _; + let mut identity_file = NamedTempFile::new().expect("failed to create tempfile"); + writeln!( + identity_file, + r"-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEAxKyYUMRCNPlb4ZV1VMofrzApu2l3wgP4Ot9wBvHsw/+RMpcHIbQK +9iQqAVp8Z+M1fJyPXTKjoJtIzuCLF6Sjo0KI7/tFTh+yPnA5QYNLZOIRZb8skumL4gwHww +5Z942FDPuUDQ30C2mZR9lr3Cd5pA8S1ZSPTAV9QQHkpgoS8cAL8QC6dp3CJjUC8wzvXh3I +oN3bTKxCpM10KMEVuWO3lM4Nvr71auB9gzo1sFJ3bwebCZIRH01FROyA/GXRiaOtJFG/9N +nWWI/iG5AJzArKpLZNHIP+FxV/NoRH0WBXm9Wq5MrBYrD1NQzm+kInpS/2sXk3m1aZWqLm +HF2NKRXSbQAAA8iI+KSniPikpwAAAAdzc2gtcnNhAAABAQDErJhQxEI0+VvhlXVUyh+vMC +m7aXfCA/g633AG8ezD/5EylwchtAr2JCoBWnxn4zV8nI9dMqOgm0jO4IsXpKOjQojv+0VO +H7I+cDlBg0tk4hFlvyyS6YviDAfDDln3jYUM+5QNDfQLaZlH2WvcJ3mkDxLVlI9MBX1BAe +SmChLxwAvxALp2ncImNQLzDO9eHcig3dtMrEKkzXQowRW5Y7eUzg2+vvVq4H2DOjWwUndv +B5sJkhEfTUVE7ID8ZdGJo60kUb/02dZYj+IbkAnMCsqktk0cg/4XFX82hEfRYFeb1arkys +FisPU1DOb6QielL/axeTebVplaouYcXY0pFdJtAAAAAwEAAQAAAP8u3PFuTVV5SfGazwIm +MgNaux82iOsAT/HWFWecQAkqqrruUw5f+YajH/riV61NE9aq2qNOkcJrgpTWtqpt980GGd +SHWlgpRWQzfIooEiDk6Pk8RVFZsEykkDlJQSIu2onZjhi5A5ojHgZoGGabDsztSqoyOjPq +6WPvGYRiDAR3leBMyp1WufBCJqAsC4L8CjPJSmnZhc5a0zXkC9Syz74Fa08tdM7bGhtvP1 +GmzuYxkgxHH2IFeoumUSBHRiTZayGuRUDel6jgEiUMxenaDKXe7FpYzMm9tQZA10Mm4LhK +5rP9nd2/KRTFRnfZMnKvtIRC9vtlSLBe14qw+4ZCl60AAACAf1kghlO3+HIWplOmk/lCL0 +w75Zz+RdvueL9UuoyNN1QrUEY420LsixgWSeRPby+Rb/hW+XSAZJQHowQ8acFJhU85So7f +4O4wcDuE4f6hpsW9tTfkCEUdLCQJ7EKLCrod6jIV7hvI6rvXiVucRpeAzdOaq4uzj2cwDd +tOdYVsnmQAAACBAOVxBsvO/Sr3rZUbNtA6KewZh/09HNGoKNaCeiD7vaSn2UJbbPRByF/o +Oo5zv8ee8r3882NnmG808XfSn7pPZAzbbTmOaJt0fmyZhivCghSNzV6njW3o0PdnC0fGZQ +ruVXgkd7RJFbsIiD4dDcF4VCjwWHfTK21EOgJUA5pN6TNvAAAAgQDbcJWRx8Uyhkj2+srb +3n2Rt6CR7kEl9cw17ItFjMn+pO81/5U2aGw0iLlX7E06TAMQC+dyW/WaxQRey8RRdtbJ1e +TNKCN34QCWkyuYRHGhcNc0quEDayPw5QWGXlP4BzjfRUcPxY9cCXLe5wDLYsX33HwOAc59 +RorU9FCmS/654wAAABFyb290QDhjNTBmZDRjMzQ1YQECAw== +-----END OPENSSH PRIVATE KEY-----" + ) + .expect("failed to write identity file"); + + let mut file = NamedTempFile::new().expect("failed to create tempfile"); + + // let's declare a couple of hosts + writeln!( + file, + r#" +Host test1 + HostName test1.example.com + Port 2200 + +Host test2 + HostName test2.example.com + User test2user + +Host test3 + HostName test3.example.com + User test3user + Port 2222 + IdentityFile {identity_path} +"#, + identity_path = identity_file.path().display() + ) + .expect("failed to write ssh config"); + + SshTestConfig { + config: file, + identity_file, + } + } +} diff --git a/src/system/config_client.rs b/src/system/config_client.rs index e7b9aa1..90fe0aa 100644 --- a/src/system/config_client.rs +++ b/src/system/config_client.rs @@ -300,19 +300,18 @@ impl ConfigClient { /// Get ssh key from host. /// None is returned if key doesn't exist - /// `std::io::Error` is returned in case it was not possible to read the key file - pub fn get_ssh_key(&self, mkey: &str) -> std::io::Result> { + pub fn get_ssh_key(&self, mkey: &str) -> Option { if self.degraded { - return Ok(None); + return None; } // Check if Key exists match self.config.remote.ssh_keys.get(mkey) { - None => Ok(None), + None => None, Some(key_path) => { // Get host and username let (host, username): (String, String) = Self::get_ssh_tokens(mkey); // Return key - Ok(Some((host, username, PathBuf::from(key_path)))) + Some((host, username, PathBuf::from(key_path))) } } } @@ -451,7 +450,7 @@ mod tests { // I/O assert!(client.add_ssh_key("Omar", "omar", "omar").is_err()); assert!(client.del_ssh_key("omar", "omar").is_err()); - assert!(client.get_ssh_key("omar").ok().unwrap().is_none()); + assert!(client.get_ssh_key("omar").is_none()); assert!(client.write_config().is_err()); assert!(client.read_config().is_err()); } @@ -493,7 +492,7 @@ mod tests { let mut expected_key_path: PathBuf = key_path; expected_key_path.push("pi@192.168.1.31.key"); assert_eq!( - client.get_ssh_key("pi@192.168.1.31").unwrap().unwrap(), + client.get_ssh_key("pi@192.168.1.31").unwrap(), ( String::from("192.168.1.31"), String::from("pi"), @@ -684,7 +683,7 @@ mod tests { ); // Iterate keys for key in client.iter_ssh_keys() { - let host: SshHost = client.get_ssh_key(key).ok().unwrap().unwrap(); + let host: SshHost = client.get_ssh_key(key).unwrap(); assert_eq!(host.0, String::from("192.168.1.31")); assert_eq!(host.1, String::from("pi")); let mut expected_key_path: PathBuf = key_path.clone(); @@ -699,7 +698,7 @@ mod tests { assert_eq!(key, rsa_key); } // Unexisting key - assert!(client.get_ssh_key("test").ok().unwrap().is_none()); + assert!(client.get_ssh_key("test").is_none()); // Delete key assert!(client.del_ssh_key("192.168.1.31", "pi").is_ok()); } diff --git a/src/system/sshkey_storage.rs b/src/system/sshkey_storage.rs index 259357a..2101b73 100644 --- a/src/system/sshkey_storage.rs +++ b/src/system/sshkey_storage.rs @@ -103,17 +103,11 @@ impl From<&ConfigClient> for SshKeyStorage { // Iterate over keys in storage for key in cfg_client.iter_ssh_keys() { match cfg_client.get_ssh_key(key) { - Ok(host) => match host { - Some((addr, username, rsa_key_path)) => { - let key_name: String = Self::make_mapkey(&addr, &username); - hosts.insert(key_name, rsa_key_path); - } - None => continue, - }, - Err(err) => { - error!("Failed to get SSH key for {}: {}", key, err); - continue; + Some((addr, username, rsa_key_path)) => { + let key_name: String = Self::make_mapkey(&addr, &username); + hosts.insert(key_name, rsa_key_path); } + None => continue, } info!("Got SSH key for {}", key); } diff --git a/src/ui/activities/auth/bookmarks.rs b/src/ui/activities/auth/bookmarks.rs index 3e70e62..06f9e7f 100644 --- a/src/ui/activities/auth/bookmarks.rs +++ b/src/ui/activities/auth/bookmarks.rs @@ -30,13 +30,13 @@ impl AuthActivity { pub(super) fn load_bookmark(&mut self, form_tab: FormTab, idx: usize) { if let Some(bookmarks_cli) = self.bookmarks_client() { // Iterate over bookmarks - if let Some(key) = self.bookmarks_list.get(idx) { - if let Some(bookmark) = bookmarks_cli.get_bookmark(key) { - // Load parameters into components - match form_tab { - FormTab::Remote => self.load_remote_bookmark_into_gui(bookmark), - FormTab::HostBridge => self.load_host_bridge_bookmark_into_gui(bookmark), - } + if let Some(key) = self.bookmarks_list.get(idx) + && let Some(bookmark) = bookmarks_cli.get_bookmark(key) + { + // Load parameters into components + match form_tab { + FormTab::Remote => self.load_remote_bookmark_into_gui(bookmark), + FormTab::HostBridge => self.load_host_bridge_bookmark_into_gui(bookmark), } } } @@ -99,13 +99,13 @@ impl AuthActivity { pub(super) fn load_recent(&mut self, form_tab: FormTab, idx: usize) { if let Some(client) = self.bookmarks_client() { // Iterate over bookmarks - if let Some(key) = self.recents_list.get(idx) { - if let Some(bookmark) = client.get_recent(key) { - // Load parameters - match form_tab { - FormTab::Remote => self.load_remote_bookmark_into_gui(bookmark), - FormTab::HostBridge => self.load_host_bridge_bookmark_into_gui(bookmark), - } + if let Some(key) = self.recents_list.get(idx) + && let Some(bookmark) = client.get_recent(key) + { + // Load parameters + match form_tab { + FormTab::Remote => self.load_remote_bookmark_into_gui(bookmark), + FormTab::HostBridge => self.load_host_bridge_bookmark_into_gui(bookmark), } } } @@ -129,10 +129,10 @@ impl AuthActivity { /// Write bookmarks to file fn write_bookmarks(&mut self) { - if let Some(bookmarks_cli) = self.bookmarks_client() { - if let Err(err) = bookmarks_cli.write_bookmarks() { - self.mount_error(format!("Could not write bookmarks: {err}").as_str()); - } + if let Some(bookmarks_cli) = self.bookmarks_client() + && let Err(err) = bookmarks_cli.write_bookmarks() + { + self.mount_error(format!("Could not write bookmarks: {err}").as_str()); } } diff --git a/src/ui/activities/auth/update.rs b/src/ui/activities/auth/update.rs index 539cbf9..5e4b69e 100644 --- a/src/ui/activities/auth/update.rs +++ b/src/ui/activities/auth/update.rs @@ -126,13 +126,13 @@ impl AuthActivity { self.host_bridge_protocol = protocol; // Update port let port: u16 = self.get_input_port(FormTab::HostBridge); - if let HostBridgeProtocol::Remote(remote_protocol) = protocol { - if Self::is_port_standard(port) { - self.mount_port( - FormTab::HostBridge, - Self::get_default_port_for_protocol(remote_protocol), - ); - } + if let HostBridgeProtocol::Remote(remote_protocol) = protocol + && Self::is_port_standard(port) + { + self.mount_port( + FormTab::HostBridge, + Self::get_default_port_for_protocol(remote_protocol), + ); } } FormMsg::RemoteProtocolChanged(protocol) => { diff --git a/src/ui/activities/auth/view.rs b/src/ui/activities/auth/view.rs index 70e2ffd..0916724 100644 --- a/src/ui/activities/auth/view.rs +++ b/src/ui/activities/auth/view.rs @@ -687,30 +687,30 @@ impl AuthActivity { /// mount release notes text area pub(super) fn mount_release_notes(&mut self) { - if let Some(ctx) = self.context.as_ref() { - if let Some(release_notes) = ctx.store().get_string(super::STORE_KEY_RELEASE_NOTES) { - // make spans - let info_color = self.theme().misc_info_dialog; - assert!( - self.app - .remount( - Id::NewVersionChangelog, - Box::new(components::ReleaseNotes::new(release_notes, info_color)), - vec![] - ) - .is_ok() - ); - assert!( - self.app - .remount( - Id::InstallUpdatePopup, - Box::new(components::InstallUpdatePopup::new(info_color)), - vec![] - ) - .is_ok() - ); - assert!(self.app.active(&Id::InstallUpdatePopup).is_ok()); - } + if let Some(ctx) = self.context.as_ref() + && let Some(release_notes) = ctx.store().get_string(super::STORE_KEY_RELEASE_NOTES) + { + // make spans + let info_color = self.theme().misc_info_dialog; + assert!( + self.app + .remount( + Id::NewVersionChangelog, + Box::new(components::ReleaseNotes::new(release_notes, info_color)), + vec![] + ) + .is_ok() + ); + assert!( + self.app + .remount( + Id::InstallUpdatePopup, + Box::new(components::InstallUpdatePopup::new(info_color)), + vec![] + ) + .is_ok() + ); + assert!(self.app.active(&Id::InstallUpdatePopup).is_ok()); } } diff --git a/src/ui/activities/filetransfer/components/popups/goto.rs b/src/ui/activities/filetransfer/components/popups/goto.rs index d7447d1..4797ed5 100644 --- a/src/ui/activities/filetransfer/components/popups/goto.rs +++ b/src/ui/activities/filetransfer/components/popups/goto.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use tui_realm_stdlib::Input; use tuirealm::command::{Cmd, CmdResult, Direction, Position}; @@ -158,7 +158,7 @@ impl OwnStates { .unwrap_or_else(|| PathBuf::from("/")); // if path is `.`, then return None - if parent == PathBuf::from(".") { + if parent == Path::new(".") { return Suggestion::None; } diff --git a/src/ui/activities/filetransfer/mod.rs b/src/ui/activities/filetransfer/mod.rs index 3d515ed..5416411 100644 --- a/src/ui/activities/filetransfer/mod.rs +++ b/src/ui/activities/filetransfer/mod.rs @@ -506,10 +506,10 @@ impl Activity for FileTransferActivity { /// This function must be called once before terminating the activity. fn on_destroy(&mut self) -> Option { // Destroy cache - if let Some(cache) = self.cache.take() { - if let Err(err) = cache.close() { - error!("Failed to delete cache: {}", err); - } + if let Some(cache) = self.cache.take() + && let Err(err) = cache.close() + { + error!("Failed to delete cache: {}", err); } // Disable raw mode if let Err(err) = self.context_mut().terminal().disable_raw_mode() { diff --git a/src/ui/activities/setup/actions.rs b/src/ui/activities/setup/actions.rs index 115ead6..dd27e6a 100644 --- a/src/ui/activities/setup/actions.rs +++ b/src/ui/activities/setup/actions.rs @@ -99,27 +99,14 @@ impl SetupActivity { Ok(State::One(StateValue::Usize(idx))) => Some(idx), _ => None, }; - if let Some(idx) = idx { - let key: Option = self.config().iter_ssh_keys().nth(idx).cloned(); - if let Some(key) = key { - match self.config().get_ssh_key(&key) { - Ok(opt) => { - if let Some((host, username, _)) = opt { - if let Err(err) = self.delete_ssh_key(host.as_str(), username.as_str()) - { - // Report error - self.mount_error(err.as_str()); - } - } - } - Err(err) => { - // Report error - self.mount_error( - format!("Could not get ssh key \"{key}\": {err}").as_str(), - ); - } - } - } + // get ssh key and delete it + if let Some(Err(err)) = idx + .and_then(|i| self.config().iter_ssh_keys().nth(i).cloned()) + .and_then(|key| self.config().get_ssh_key(&key)) + .map(|(host, username, _)| self.delete_ssh_key(host.as_str(), username.as_str())) + { + // Report error + self.mount_error(err.as_str()); } } diff --git a/src/ui/activities/setup/config.rs b/src/ui/activities/setup/config.rs index ae49445..d26e086 100644 --- a/src/ui/activities/setup/config.rs +++ b/src/ui/activities/setup/config.rs @@ -77,16 +77,11 @@ impl SetupActivity { Some(key) => { // Get key path match ctx.config().get_ssh_key(key) { - Ok(ssh_key) => match ssh_key { - None => Ok(()), - Some((_, _, key_path)) => { - match edit::edit_file(key_path.as_path()) { - Ok(_) => Ok(()), - Err(err) => Err(format!("Could not edit ssh key: {err}")), - } - } + None => Ok(()), + Some((_, _, key_path)) => match edit::edit_file(key_path.as_path()) { + Ok(_) => Ok(()), + Err(err) => Err(format!("Could not edit ssh key: {err}")), }, - Err(err) => Err(format!("Could not read ssh key: {err}")), } } None => Ok(()), diff --git a/src/ui/activities/setup/view/ssh_keys.rs b/src/ui/activities/setup/view/ssh_keys.rs index 7dba30f..56933e1 100644 --- a/src/ui/activities/setup/view/ssh_keys.rs +++ b/src/ui/activities/setup/view/ssh_keys.rs @@ -126,7 +126,7 @@ impl SetupActivity { .config() .iter_ssh_keys() .map(|x| { - let (addr, username, _) = self.config().get_ssh_key(x).ok().unwrap().unwrap(); + let (addr, username, _) = self.config().get_ssh_key(x).unwrap(); format!("{username} at {addr}") }) .collect();