277 Commits

Author SHA1 Message Date
veeso
54b674ad43 ci: windows artifact name
Some checks failed
Deploy static content to Pages / deploy (push) Has been cancelled
Windows / build (push) Has been cancelled
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Close inactive issues / close-issues (push) Has been cancelled
2025-11-11 12:34:36 +01:00
veeso
c32822037e ci: deploy site 2025-11-11 12:21:05 +01:00
veeso
abb5c212c5 feat: Merge branch '0.19.0' 2025-11-11 12:19:21 +01:00
veeso
e9b54a227b chore: CHANGELOG date 2025-11-11 09:42:21 +01:00
veeso
befc32198a ci: debian fix
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2025-11-10 17:25:29 +01:00
veeso
7e5103ff7e ci: Debian 2025-11-10 17:06:44 +01:00
veeso
2cb600083e docs: Release date 2025-11-10 16:44:24 +01:00
Christian Visintin
47d23673e6 ci: Build artifacts for Windows x86_64 and Ubuntu x86_64 (#368) 2025-11-10 16:43:25 +01:00
Christian Visintin
a0b357cf8c feat: Added <CTRL+S> keybinding to get the total size of selected paths. (#367)
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
* feat: Added `<CTRL+S>` keybinding to get the total size of selected paths.

closes #297
2025-11-09 21:14:42 +01:00
Christian Visintin
75943f2b93 feat: Changed file overwrite behaviour (#366)
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
Now the user can choose for each file whether to overwrite, skip or overwrite all/skip all.

closes #335
2025-11-09 19:00:17 +01:00
veeso
085ab721f9 build: remotefs-ssh 0.7.1
This version fixes compatibility with hosts which don't use bash/sh as the default shell.

closes #365
2025-11-09 17:38:50 +01:00
Christian Visintin
f4156a5059 feat: Import bookmarks from ssh config with a CLI command (#364)
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
* feat: Import bookmarks from ssh config with a CLI command

Use import-ssh-hosts to import all the possible hosts by the configured ssh config or the default one on your machine

closes #331
2025-11-08 15:32:52 +01:00
Christian Visintin
4bebec369f fix: Issues with update checks (#363)
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
Removed error popup message if failed to check for updates.
Prevent long timeouts when checking for updates if the network is down or the DNS is not working.

closes #354
2025-10-02 21:27:51 +02:00
Christian Visintin
05c8613279 fix: Report a message while calculating total size of files to transfer. (#362)
* fix: Report a message while calculating total size of files to transfer.

Currently, in case of huge transfers the app may look frozen while calculating the transfer size. We should at least report to the user we are actually doing something.

closes #361

* ci: windows runner
2025-10-02 20:58:26 +02:00
veeso
205d2813ad perf: Migrated to libssh.org on Linux and MacOS for better ssh agent support.
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
closes #337
2025-09-20 18:13:20 +02:00
veeso
86660a0cc9 fix: SMB support for MacOS with vendored build of libsmbclient.
closes #334
2025-09-20 18:07:26 +02:00
veeso
05830db206 docs: User manual and get started links
Some checks failed
Install.sh / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
Linux / build (push) Has been cancelled
Close inactive issues / close-issues (push) Has been cancelled
2025-09-16 10:36:17 +02:00
veeso
3c79e812eb build: 0.19 deps 2025-09-06 16:40:01 +02:00
moshyfawn
0287e7706a fix: typo in file open error message (#349)
Some checks failed
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
Close inactive issues / close-issues (push) Has been cancelled
2025-06-13 22:50:06 +02:00
veeso
67a14c2725 fix: lock
Some checks failed
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2025-06-10 21:20:04 +02:00
veeso
df03c5c1bf feat: 0.18
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2025-06-10 14:29:02 +02:00
veeso
3ce3ffee3d fix: larger file info popup 2025-06-10 14:26:36 +02:00
Christian Visintin
c0b32a1847 feat: Replaced the Exec popup with a fully functional terminal emulator (#348)
Some checks are pending
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
* feat: Replaced the `Exec` popup with a fully functional terminal emulator

closes #340

* fix: colors and fmt for terminal

* feat: Handle exit and cd on terminal

* fix: Fmt pah
2025-06-10 13:17:20 +02:00
Christian Visintin
81ae0035c3 Fix SSH auth with id keys (#347)
I fixed the id_rsa/id_ed25519 SSH auth issue on Mac and now termscp should respect the key-based authentication, just like the regular ssh user@hostname, without the need for any ssh agents.

---

Co-authored-by: Lucas Czekaj <lukasz@czekaj.us>
2025-06-08 18:34:59 +02:00
veeso
783da22ca2 feat: **Updated dependencies** and updated the Rust edition to 2024 2025-06-08 18:00:42 +02:00
veeso
8715c2b6f9 chore: CODE_OF_CONDUCT update
Some checks failed
Install.sh / build (push) Has been cancelled
2025-05-10 19:23:06 +02:00
veeso
98a748dccc style: catppuccin themes
Some checks failed
Install.sh / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
Linux / build (push) Has been cancelled
2025-04-15 12:24:08 +02:00
Christian Visintin
bef031a414 Update website.yml
Some checks failed
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2025-03-23 22:01:18 +01:00
veeso
ce0e953182 chore: site 2025-03-23 18:13:05 +01:00
veeso
9a5caf75c3 build: so apparently native-tls vendored tries to build openssl on windows, wtf guys?
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2025-03-23 18:07:20 +01:00
veeso
446f4a3a32 build: build docker for x86 2025-03-23 16:43:51 +01:00
veeso
da75912d26 docs: version
Some checks are pending
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
2025-03-23 15:59:50 +01:00
veeso
4ed23c2a18 build: aws-s3 0.4.2 2025-03-23 15:58:25 +01:00
Christian Visintin
23ae334bef ci(build): build vendored smb and refactor platform deps (#333) 2025-03-23 15:57:54 +01:00
Christian Visintin
ec75ae1486 feat: 132 queuing transfers (#332)
the logic of selecting files has been extended!
From now on selecting file will put the files into a transfer queue, which is shown on the bottom panel.
When a file is selected the file is added to the queue with a destination path, which is the **current other explorer path at the moment of selection.
It is possible to navigate to the transfer queue by using `P` and pressing `ENTER` on a file will remove it from the transfer queue.Other commands will work as well on the transfer queue, like `COPY`, `MOVE`, `DELETE`, `RENAME`.

closes #132
2025-03-23 14:36:13 +01:00
veeso
368570592f feat(cli): added --wno-keyring flag to disable keyring
Some checks are pending
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
closes #308
2025-03-22 13:44:02 +01:00
veeso
806793421e fix(bookmarks): Local directory path is not switching to what's specified in the bookmark
closes #316
2025-03-22 13:25:29 +01:00
veeso
1f377b242d fix(log): add suppaftp/pavao/kube to allowed logs
Some checks failed
Windows / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
fix #330
2025-03-17 18:59:47 +01:00
veeso
a4906b129a docs: veeso.me instead of veeso.dev
Some checks are pending
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
2025-03-17 09:31:44 +01:00
veeso
5c6e8925ad test(remotefs_builder): check result, build doesn't panic anymore 2025-03-17 09:30:33 +01:00
veeso
a18eff689d fix(aws-s3): updated remotefs-aws-s3 to 0.4.1
Some checks are pending
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
should fix #329
2025-03-16 20:06:35 +01:00
veeso
274742d6d9 build: bump to ssh2-config 0.4 and remotefs 0.6 to have support for Include in config files
Some checks are pending
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
fix #309
2025-03-15 20:04:21 +01:00
veeso
cdebcbd4dc fix: the return value of --version should be 0
fix #317
2025-03-15 16:54:36 +01:00
veeso
cdf303a847 fix: fixed a crash when the local directory specified in the auth form does not exist
fix #319
2025-03-15 16:46:57 +01:00
veeso
dd35fe825c fix(ui): fixed input mask on host bridge on local dir up
if you go up on local dir when localhost is selected it panics

fix #327
2025-03-15 14:24:24 +01:00
veeso
5c4a971aca docs(CONTRIBUTING): docs(CONTRIBUTING): mistakes
fix #318
2025-03-15 14:19:18 +01:00
veeso
7522b4d0ff chore(changelog): changelog 2025-03-15 14:16:18 +01:00
veeso
b0f314837e build(deps): updated dependencies and edition to 2024 2025-03-15 14:15:45 +01:00
Christian Visintin
8a9ba7745a Merge pull request #325 from eggplants/fix-clippy-error
Some checks failed
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
fix: clippy error
2025-01-06 12:53:13 +01:00
haruna
b7d75a2749 fix: clippy error 2025-01-05 22:52:45 +09:00
Christian Visintin
fe0d9b0aa6 Update stale.yml
Some checks failed
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
2024-12-28 13:22:03 +01:00
veeso
7dba691ccc fix: isolated-tests for localhost
Some checks failed
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-11-13 17:06:34 +01:00
veeso
099e2154ba fix: unused import isolated tests 2024-11-13 15:57:49 +01:00
veeso
f2efb25ad7 fix: 0.16.1
Some checks are pending
Install.sh / build (push) Waiting to run
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
2024-11-12 12:34:26 +01:00
veeso
e45c3d5b4e fix: gg rust 1.82 for introducing a nice breaking change in config which was not mentioned in changelog
Some checks failed
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-10-21 11:09:50 +02:00
veeso
69f821baef fix: cfg unix forbidden in rust .82
Some checks are pending
Install.sh / build (push) Waiting to run
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
2024-10-21 10:32:50 +02:00
Christian Visintin
11559d0962 Merge pull request #302 from veeso/0.16
Some checks failed
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
0.16
2024-10-14 16:36:36 +02:00
veeso
79c33095fc fix: tiny ui issue 2024-10-14 16:00:15 +02:00
veeso
0ec6bcbcef fix: 0.16
Some checks failed
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
Linux / build (push) Has been cancelled
2024-10-14 11:40:45 +02:00
Christian Visintin
3cde067339 feat: Show .. directory before all the others in the explorer to navigate to the parent dir (#301) 2024-10-14 11:28:02 +02:00
Christian Visintin
c05ef32270 fix: issue 292 New version alert was not displayed due to a semver regex issue. (#300) 2024-10-14 10:43:47 +02:00
Christian Visintin
7eb913ec7b fix: tuirealm 2.x (#299) 2024-10-14 09:55:52 +02:00
veeso
4e63093d25 fix: users from lock
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-10-07 17:50:15 +02:00
Christian Visintin
e5d50698d2 fix: vergen (#296) 2024-10-07 17:49:52 +02:00
Christian Visintin
79c31c2d84 fix: Use uzers instead of the dead package users which has several vulnerabilities (#295) 2024-10-07 17:40:35 +02:00
Christian Visintin
aab266a661 285 feature request multi host (#293) 2024-10-07 16:27:45 +02:00
veeso
a4c9acb49f feat: version 0.16 2024-10-05 17:41:40 +02:00
veeso
6205c7f3c5 fix: include build.rs
Some checks failed
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-10-03 17:57:49 +02:00
veeso
e4af014013 fix: readme 2024-10-03 17:56:51 +02:00
Christian Visintin
c9f649f40f Merge pull request #288 from veeso/0.15 2024-10-03 17:55:50 +02:00
veeso
1f27ca2607 fix: ci 2024-10-03 17:36:44 +02:00
veeso
a1288c7480 fix: github ci is stable and reliable (one worker broken each 2 weeks) 2024-10-03 17:28:29 +02:00
veeso
4bfec52ba5 fix: set date 2024-10-03 17:12:45 +02:00
Christian Visintin
3f01be3baa 280 feature request go to path auto completion (#287) 2024-10-03 17:11:25 +02:00
Christian Visintin
8e2ffeabce fix: isolated-tests feature to run tests for releasing on distributions which run in isolated environments (#286)
* fix: `isolated-tests` feature to run tests for releasing on distributions which run in isolated environments

* fix: cond
2024-10-03 12:17:03 +02:00
Christian Visintin
fc68e2621b feat: it is now possible to cancel find command; show find progress (#284) 2024-10-03 11:31:16 +02:00
Christian Visintin
b2a8a3041c 249 feature request better search results (#282)
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
* feat: issue 249 - fuzzy search replaced the old find explorer

* fix: forgot to upload file

* fix: removed debug
2024-10-02 17:45:48 +02:00
veeso
c507d54700 fix: popup texts
Some checks are pending
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
2024-10-02 12:59:53 +02:00
veeso
31c5ad7534 fix: issue 277 Fix a bug in the configuration page, which caused being stuck if the added SSH key was empty 2024-10-02 12:44:35 +02:00
veeso
14ac10547c fix: don't clear screen after terminating termscp 2024-10-02 12:34:00 +02:00
Christian Visintin
ae1638ee17 feat: Pods and container explorer for Kube protocol (#281) 2024-10-02 12:24:46 +02:00
veeso
c5f76ec51c fix: bump vers 2024-10-02 10:33:42 +02:00
veeso
d319a2fae4 fix: notify 6 2024-10-02 10:25:30 +02:00
veeso
72a5703a08 fix: keyring test not passing macos 2024-10-02 10:09:09 +02:00
veeso
91b4d4e463 fix: bump vers 2024-09-30 12:06:42 +02:00
veeso
17719ea370 feat: init 0.15 2024-09-30 12:06:03 +02:00
veeso
707a3faa54 fix: dbus deveL
Some checks failed
Coverage / build (push) Has been cancelled
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-08-06 09:26:49 +02:00
veeso
dfe58e6147 fix: tokio rt builder
Some checks failed
Coverage / build (push) Has been cancelled
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-07-22 10:36:16 +02:00
veeso
c49dab3888 fix: changelog
Some checks failed
Coverage / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
Install.sh / build (push) Has been cancelled
2024-07-17 17:05:15 +02:00
veeso
47ff07e496 feat: termscp 0.14 2024-07-17 16:22:53 +02:00
veeso
61a8fb95e4 fix: removed support for RPM 2024-07-17 12:41:49 +02:00
Christian Visintin
f757336d75 feat: kube protocol support (#267) 2024-07-17 11:59:30 +02:00
veeso
cf529c1678 fix: german manual
Some checks failed
Linux / build (push) Has been cancelled
Coverage / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-07-15 15:20:29 +02:00
Christian Visintin
631f09b9a8 feat: issue 256 - filter files (#266) 2024-07-15 15:08:22 +02:00
Eric Long
65aed76605 chore: bump ring to 0.17 (#265) 2024-07-15 11:52:55 +02:00
veeso
9036d83635 fix: remotefs-ssh 0.3.1
Some checks failed
Coverage / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled
2024-07-09 12:25:47 +02:00
Christian Visintin
179c4de4ed feat: ssh-agent (#264) 2024-07-09 11:55:17 +02:00
Christian Visintin
f3b84c97e1 feat: ALT+A to deselect all files (#263)
Some checks are pending
Coverage / build (push) Waiting to run
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
2024-07-08 15:56:20 +02:00
Christian Visintin
b5b3aeb645 fix: Jump to next entry after select (#262) 2024-07-08 15:26:27 +02:00
veeso
e5172d4207 fix: sorted flags in readme 2024-07-08 15:24:42 +02:00
Christian Visintin
50e7f5f5d0 fix: CLI remote args cannot handle '@' in the username (#261)
Some checks are pending
Coverage / build (push) Waiting to run
Linux / build (push) Waiting to run
MacOS / build (push) Waiting to run
Windows / build (push) Waiting to run
2024-07-08 14:57:20 +02:00
veeso
88cdae79a8 fix: lint 2024-07-08 14:48:03 +02:00
Michał Sieroń
4f3b97b198 fix: correct help text for update subcommand (#259)
Some checks failed
Windows / build (push) Has been cancelled
Coverage / build (push) Has been cancelled
Install.sh / build (push) Has been cancelled
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
2024-06-25 22:38:59 +02:00
Hartur Alcantara
54a8317d0e Adding Brazilian Portuguese translation (#253) 2024-05-08 08:52:34 +02:00
Orhun Parmaksız
3a46aa74f9 chore: update tui-rs references to ratatui (#244) 2024-04-18 15:59:31 +02:00
Orhun Parmaksız
aca5b37898 docs: update Arch Linux instructions (#243) 2024-04-17 19:26:35 +02:00
veeso
0394a12c9f fix: install script version 2024-03-02 20:42:48 +01:00
Christian Visintin
e61d04aa1b Merge pull request #236 from veeso/develop
0.13.0
2024-03-02 20:27:16 +01:00
veeso
c0c9f7c0dd fix: lint??? 2024-03-02 19:41:07 +01:00
veeso
905fe5fc9f fix: debian script 2024-03-02 19:36:01 +01:00
veeso
89ab53a71b fix: debian script 2024-03-02 19:35:18 +01:00
veeso
7dccac6105 fix: test 2024-03-02 19:31:36 +01:00
veeso
44051ec718 feat: termscp 0.13.0 2024-03-02 19:28:01 +01:00
Christian Visintin
c7469b8594 feat: WebDAV support (#235) 2024-03-02 19:23:27 +01:00
veeso
5dfee2cbd9 fix: AWS S3 wasn't working anymore due to rust-s3 outdate 2024-03-01 17:02:58 +01:00
Christian Visintin
679a829744 233 feature request subcommands (#234) 2024-03-01 10:01:25 +01:00
PIRADATA
2a51ab984c update linux installation command from termscp.veeso.dev/get-started.html (#223) 2023-12-15 18:53:45 +01:00
Jarod
2b2ebadd6a Fixed formatting (#207) 2023-12-15 09:33:55 +01:00
Christian Visintin
2b15a23fe8 Update README.md 2023-11-15 21:50:49 +01:00
veeso
d30c3dfadd force tuirealm 1.8 2023-10-06 22:03:08 +02:00
veeso
ef8dbb6305 0.12.3 2023-10-06 09:19:03 +02:00
veeso
623ba806e1 0.12.3 2023-10-06 09:17:38 +02:00
veeso
ea9dd03f55 Revert "feat: tui-realm 1.9"
This reverts commit cfbecc049d.
2023-10-06 09:13:57 +02:00
veeso
92d20f33fe new site 2023-10-01 16:20:35 +02:00
veeso
15caef83e6 0.12.2 2023-10-01 16:20:04 +02:00
veeso
19992402e2 fix: panic if the terminal screen is too small 2023-10-01 16:18:11 +02:00
veeso
182bbb94a2 0.12.2 2023-10-01 16:12:47 +02:00
Christian Visintin
20c3e22572 [BUG] - termscp not respecting port in ssh config (#216) 2023-10-01 16:12:43 +02:00
veeso
d3c2c084db fix: fmt 2023-08-23 10:11:13 +02:00
veeso
cfbecc049d feat: tui-realm 1.9 2023-08-23 09:18:09 +02:00
Christian Visintin
9de171fb83 added cfg smb-windows to be able to disable SMB on windows (#210)
* added cfg smb-windows to be able to disable SMB on windows

* lint
2023-08-20 10:24:34 +02:00
veeso
2f48c765e3 termscp 0.12.0 2023-07-06 16:17:33 +02:00
Christian Visintin
ca005cbecd save local file paths in bookmark (#204)
* fix: renamed Bookmark 'directory' to 'remote_path' (keep name in file)

* feat: local_path as file transfer parameter and in bookmark
2023-07-06 16:05:22 +02:00
Christian Visintin
ee28d34f29 fix: don't update path breadcrumb if enter/scan dir failed (#203) 2023-07-06 14:55:53 +02:00
veeso
295191b9eb Merge branch 'main' into develop 2023-07-06 11:49:06 +02:00
veeso
16b2aa8596 fix: rustup target 2023-07-06 11:38:38 +02:00
Christian Visintin
522ee0355e feat: build artifacts workflow (#202) 2023-07-06 11:26:14 +02:00
veeso
e5ca956897 fix: don't run CI on site/.md change 2023-07-06 11:07:22 +02:00
Christian Visintin
a071f3d420 feat: smb is now an optional feature (#200) 2023-07-06 11:02:53 +02:00
veeso
66888c418c fix: deps 2023-07-06 09:59:25 +02:00
veeso
b5f712fa04 fix: better main runner 2023-07-06 09:49:35 +02:00
529
1509401599 Add missing row in KeybindingsPopup (#193) 2023-07-06 09:17:55 +02:00
veeso
6506f4ae59 fixed theme 2023-07-05 13:22:56 +02:00
veeso
5a5fa52b57 fixed theme 2023-07-05 12:58:21 +02:00
veeso
b7d4c68ebe new termscp site 2023-07-05 12:33:17 +02:00
Renan Dorneles Schuquel
00a6c53178 Fix: Some URL typos on 'install.sh' and 'README.md'. (#197)
Co-authored-by: rschuquel <renan.schuquel@unimedvtrp.com.br>
2023-06-23 21:54:38 +02:00
Christian Visintin
67bc1a2a08 Ignore backlog issues 2023-05-23 09:20:11 +02:00
Christian Visintin
0bb3c9a26e Create stale.yml 2023-05-22 23:22:57 +02:00
veeso
4394941c71 fix: readme site links 2023-05-20 15:01:22 +02:00
veeso
175ea23bfc fix: sh compliant macos.sh build script 2023-05-18 11:53:21 +02:00
veeso
cef100e5d9 fix: install workflow 2023-05-18 11:42:24 +02:00
veeso
afba6c32c5 fix: release date 2023-05-16 15:52:50 +02:00
veeso
31f5bd095b fix: macos script 2023-05-16 14:38:16 +02:00
veeso
e1add0ed28 fix: pavao 0.2.3 2023-05-16 09:29:57 +02:00
veeso
79bc6a684b fix: pavao 0.2.2 2023-05-16 09:27:48 +02:00
veeso
bae4db8e27 fix: build 2023-05-15 14:23:13 +02:00
veeso
4cbba3f3cb fix: release date 2023-05-13 18:11:07 +02:00
veeso
e9fbb7f317 fix: specify ssh2 config params 2023-05-13 17:59:24 +02:00
Christian Visintin
044f2436f8 Don't prompt for password if a ssh key is set for that host (#186)
* feat: don't ask password if a ssh key is set for that host

* fix: User from ssh config was not used as it should

* fix: forgot a file
2023-05-13 16:09:37 +02:00
Christian Visintin
b7369162d2 SMB support (#184)
* feat: smb client

* fix: smb connection

* fix: smbclient deps

* feat: SMB mentions to user manual

* feat: changelog

* dlib macos

* fix: removed smb support from macos :(

* fix: restored libsmbclient build

* fix: strange lint message

* fix: macos build smb

* fix: macos build smb

* fix: macos tests

* fix: macos lint

* feat: SMB windows support

* fix: windows tests
2023-05-13 15:00:16 +02:00
Christian Visintin
a13663e5e9 Brew Linux support (#185)
* feat: brew linux and arm installation

* fix: updated website refs to termscp.veeso.dev

* feat: added brew installation to website
2023-05-12 17:06:27 +02:00
Christian Visintin
79dd9e2303 chmod popup (#183)
* feat: chmod popup

* fix: windows shall not allows chmod on localhost
2023-05-10 17:04:24 +02:00
Christian Visintin
b4fa50a666 feat: allow unknown fields in ssh2 configuration file (#181) 2023-05-10 09:27:54 +02:00
Christian Visintin
5a67fc7b0e fix: #153 show a loading message when loading directory's content (#180) 2023-05-09 17:43:37 +02:00
veeso
9dab34e7ee rustfmt.toml 2023-05-09 15:40:28 +02:00
veeso
c5eeae74b7 fmt 2023-05-09 15:40:21 +02:00
Christian Visintin
9009002b6e debug log belongs in cache directory not config directory (#179)
* log files are now written to cache dir instead of config dir

* lint

* fmt
2023-05-09 15:32:42 +02:00
veeso
9bf23b3f6b working on 0.12 2023-05-09 12:48:51 +02:00
veeso
3ec94c17bc 0.11.3 2023-04-19 11:07:42 +02:00
veeso
ed8ba628e5 feat: site improvements 2023-04-19 11:01:44 +02:00
veeso
7c638473d6 0.11.3 2023-04-19 10:17:59 +02:00
Christian Visintin
d37140ead6 fix: relative paths windows (#167) 2023-04-19 10:15:00 +02:00
veeso
fdb0d97a61 rtd 2023-04-18 18:10:40 +02:00
veeso
0c1e9c0d60 feat: site 0.11.2 2023-04-18 11:59:13 +02:00
veeso
e1a2255a58 feat: dependencies up-to-date 2023-04-18 11:58:10 +02:00
Christian Visintin
f6b2c814c0 bump remotefs-ssh to 0.1.5 (#164) 2023-04-18 11:44:49 +02:00
delta2force
efb30231ee update Cargo.lock (#157) 2023-03-23 14:05:12 +01:00
veeso
8cb6c19210 updated curl 2023-03-08 12:07:25 +01:00
veeso
51c2618b5a optimized docker builds (re-use containers) 2023-03-08 11:49:09 +01:00
veeso
279df59b5d install ci 2023-03-07 21:01:29 +01:00
veeso
d8373d0eba 0.11.1 2023-03-07 09:31:21 +01:00
veeso
74fe97f2e2 Don't tell me you're too blind to see 2023-03-06 11:16:40 +01:00
veeso
e62f15f375 gb.png 2023-03-06 11:15:44 +01:00
veeso
21dc73b556 Bump ssh2-config to 0.1.6 2023-03-03 12:13:19 +01:00
veeso
a10325f6fb removed remove_dir_all crate with tempfile 3.4 2023-02-28 11:09:57 +01:00
Christian Visintin
1ecef6fc16 issue 150: some issues with configuration (#151)
* issue 150: some issues with configuration
2023-02-28 10:45:07 +01:00
veeso
67df3dc76a working on 0.11.1 2023-02-27 12:23:01 +01:00
Christian Visintin
7ecfaea278 Update FUNDING.yml 2023-02-27 11:50:21 +01:00
veeso
97151d18bf fixed build scripts 2023-02-22 16:06:11 +01:00
veeso
7ad7a1580d fixed serializer 2023-02-19 18:46:10 +01:00
veeso
46f2954bc4 install.yml 2023-02-19 18:24:29 +01:00
veeso
0c88f559e2 0.11.0 2023-02-19 18:23:30 +01:00
veeso
8a0979578a deps 2023-02-13 09:35:10 +01:00
veeso
7ee28a00ae planned updates 2023-02-12 22:28:43 +01:00
Christian Visintin
82330f870e Optimize transfers (#147)
* When the file is exchanged, all times attributes are set (if supported by the protocol)

* If local/remote file have the same last modification time (`mtime`), the file is not transferred
2023-02-12 22:27:42 +01:00
veeso
54aecdc478 0.11.0 2023-02-11 12:49:30 +01:00
veeso
d5038a22ee fixed tests 2023-02-11 12:45:12 +01:00
Christian Visintin
c0bc493d21 125 installation missing aarch64 linux build (#146)
aarch64 build
2023-02-11 12:26:43 +01:00
Christian Visintin
1c75c7d386 SSH configuration path is not ~/.ssh/config by default (#145)
SSH configuration path is not `~/.ssh/config` by default
2023-02-11 12:23:57 +01:00
Christian Visintin
251b125cbb 126 new feature termscp doesnt use id rsa default ssh private key to authenticate to sftp scp endpoint (#144)
fixed issue 126 <https://github.com/veeso/termcp/issues/126>
2023-02-11 12:23:56 +01:00
veeso
efd2235ff3 fmt 2023-02-11 12:23:56 +01:00
veeso
1db2ff7ec5 Popup with fixed sizes or percentage 2023-02-11 12:23:56 +01:00
veeso
4d5f3a6b63 lint 2023-02-11 12:23:56 +01:00
veeso
62003308a7 lint 2023-02-11 12:23:56 +01:00
veeso
cb037cfca9 updated dependencies 2023-02-11 12:23:56 +01:00
Sergei Akhmatdinov
15fffdf0c9 fix install script for FreeBSD, add doas priv elevation 2023-01-31 15:03:07 +01:00
veeso
c1b245b4c9 fixed install script for freebsd 2023-01-30 12:15:56 +01:00
veeso
d14225c0b9 readme 2023-01-13 09:55:49 +01:00
veeso
d60be7dc80 0.10.0 2022-12-28 10:49:36 +01:00
Christian Visintin
146a1f3ed6 Create website.yml 2022-12-27 16:44:42 +01:00
veeso
12fe10100b termscp site 2022-12-27 16:42:25 +01:00
RakerZh
298d590306 fix typo 2022-11-08 09:30:48 +01:00
pin
8e6aae08b6 Add NetBSD 2022-10-25 18:10:00 +02:00
veeso
cb33ba114e fixed check on aarch64 2022-10-25 18:09:06 +02:00
veeso
6369ead491 Merge branch '0.10.0' into main 2022-10-15 14:01:40 +02:00
veeso
ae350b4bfa termscp 0.10 2022-10-15 14:01:00 +02:00
veeso
cd5bb28fb7 updated deps 2022-10-10 18:04:44 +02:00
veeso
f27a4e2a02 lint 2022-10-10 17:40:03 +02:00
veeso
0f432d0375 fixed build 2022-10-10 17:26:26 +02:00
veeso
8b67c59247 removed deps from docker build 2022-10-10 16:50:00 +02:00
veeso
fdd7901f7e removed libssl dependency 2022-10-10 16:21:32 +02:00
Christian Visintin
2eec7c4b2b Update README.md 2022-09-06 12:01:24 +02:00
veeso
64e3848c97 Use ssh2 config IdentityFile as fallback for key based authentication 2022-08-30 17:47:55 +02:00
veeso
833cd7d3ba Fixed version comparison when going above 0.9 2022-08-30 15:54:37 +02:00
veeso
2f1b644a40 backtab will now change the explorer tab; use P to change to log 2022-08-30 15:45:26 +02:00
veeso
6a5c248d35 Yes/No dialogs are now answerable by pressing Y or N on your keyboard 2022-08-30 15:29:34 +02:00
veeso
96df152220 fixed issue 122 <https://github.com/veeso/termscp/issues/122> 2022-08-30 15:10:41 +02:00
veeso
a22c5025d7 lint 2022-08-17 10:33:31 +02:00
veeso
cce0c92c0b dependencies updated 2022-08-17 10:28:44 +02:00
veeso
90d7083b24 lazy-regex 2022-08-17 10:24:13 +02:00
veeso
b3ab76e573 working on 0.10.0 2022-08-17 10:16:03 +02:00
Christian Visintin
66913d5fc1 Update README.md 2022-08-05 14:51:28 +02:00
veeso
f5174ccac0 removed dynamic libssl dep 2022-07-20 12:37:22 +02:00
veeso
82489e7459 homebrew notice 2022-07-20 12:08:11 +02:00
eric wong
ad562a7b09 Optimize the presentation of zh-CN/README.md (#117) 2022-07-18 09:31:31 +02:00
veeso
08c42e5acf release date 2022-06-18 13:35:03 +02:00
veeso
aac9cf4fa0 features updated 2022-06-10 12:18:38 +02:00
veeso
a26b21da89 0.9.0 2022-06-09 17:45:17 +02:00
veeso
bb95c9a4d0 updated dependencies 2022-06-09 15:11:55 +02:00
veeso
80dea3f71a Fixed SSH key list showing {hostname} at {username} instead of {username} at {hostname} 2022-06-09 15:08:02 +02:00
veeso
0057a657d2 removed license headers 2022-06-09 14:28:02 +02:00
Christian Visintin
816270d545 Fs watcher (#113)
fs watcher
2022-06-09 13:03:02 +02:00
veeso
2caa0432df Remote directory path in authentication form and in bookmarks parameters 2022-05-03 15:37:00 +02:00
Christian Visintin
e0d8b80cdf Bookmark name as hostname for cli args (#111)
bookmark name as hostname for cli args
2022-05-03 11:54:48 +02:00
veeso
f094979ddb working on 0.9.0 2022-05-03 09:16:38 +02:00
veeso
0c8144aaa8 0.8.2 2022-04-26 21:41:21 +02:00
veeso
3249e82873 lint 2022-04-22 09:56:10 +02:00
veeso
66adad3135 Fixed termscp panics when displaying long non-ascii filenames 2022-04-20 12:09:33 +02:00
veeso
f2e5bf4441 Working on 0.8.2 2022-04-07 11:08:47 +02:00
veeso
601b0595d4 Write exitcode on exit 2022-04-07 11:07:41 +02:00
veeso
c47fcb2225 fixed install script 2022-04-07 10:24:54 +02:00
veeso
550c7ca62a upcoming features 2022-03-22 20:55:54 +01:00
veeso
3256c276b4 0.8.1 2022-03-22 20:45:24 +01:00
veeso
04f43fff63 boolean release 2022-03-19 10:35:36 +01:00
veeso
82e8c84000 fixed make_pkg 2022-03-15 12:22:43 +01:00
veeso
31203d76ce install.sh m1 macos 2022-03-15 11:25:50 +01:00
veeso
572a948f2c macos arm64 build 2022-03-15 11:25:50 +01:00
veeso
b6ee49cfa6 updated donation link in install.sh 2022-03-09 17:07:35 +01:00
veeso
0334c5db78 Updated dependencies 2022-03-09 16:19:57 +01:00
veeso
c45ebec261 Fixed AltGr characters not allowed in auth form 2022-03-09 15:13:08 +01:00
veeso
ad2781b62c use latest rust in macos/windows ci 2022-03-09 11:27:26 +01:00
veeso
35dc11cce3 Strip binary with new 1.59 feature 2022-03-05 11:11:07 +01:00
veeso
8d9e7443ec updated user manuals 2022-03-05 11:06:14 +01:00
veeso
697ab225ea clippy 2022-03-05 11:06:14 +01:00
veeso
babbc5eadb new-path-style and endpoint s3 params 2022-03-05 11:06:14 +01:00
veeso
f28dba7660 added new s3 params 2022-03-05 11:06:14 +01:00
veeso
c5eba4b56a changed 'AWS S3' to 'S3' in forms 2022-03-05 11:06:14 +01:00
veeso
0b70819781 wtf git? 2022-02-06 11:09:44 +01:00
veeso
069fe8cae2 Merge branch '0.8.1' of github.com:veeso/termscp into 0.8.1 2022-02-06 10:57:44 +01:00
veeso
043f54e707 removed freebsd workflow. It is not supported anymore 2022-02-06 10:57:27 +01:00
veeso
b635554e52 updated freebsd vm version 2022-02-04 15:16:07 +01:00
veeso
9e35616568 updated dependencies 2022-02-04 15:14:11 +01:00
veeso
615dbda583 clippy 2022-02-04 15:06:11 +01:00
veeso
4b421a4a87 issue 94: color not reset after leaving text editor (SORCERY!!!) 2022-01-29 19:26:37 +01:00
veeso
0fe06eb52b updated deps 2022-01-29 19:04:22 +01:00
veeso
e8c6b8306f working on 0.8.1 2022-01-29 19:03:12 +01:00
Pascal Sommer
d1457253c4 fix: footer listed "Delete" shortcut as "Make Dir" 2022-01-12 21:03:15 +01:00
215 changed files with 28512 additions and 10747 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1 +0,0 @@
ko_fi: veeso

View File

@@ -8,6 +8,7 @@ ignore:
- "../*"
- src/main.rs
- src/activity_manager.rs
- src/cli_opts.rs
- src/support.rs
- src/system/notifications.rs
- "src/ui/activities/*"

161
.github/workflows/build-artifacts.yml vendored Normal file
View File

@@ -0,0 +1,161 @@
name: "Build artifacts"
on:
workflow_dispatch:
env:
TERMSCP_VERSION: "0.19.0"
jobs:
build-binaries:
name: Build - ${{ matrix.platform.release_for }}
strategy:
matrix:
platform:
- release_for: MacOS-x86_64
os: macos-latest
platform: macos
target: x86_64-apple-darwin
- release_for: MacOS-aarch64
os: macos-latest
platform: macos
target: aarch64-apple-darwin
- release_for: Linux-x86_64
os: ubuntu-latest
platform: linux
target: x86_64-unknown-linux-gnu
debian_suffix: amd64
- release_for: Windows-x86_64
os: windows-latest
platform: windows
target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.platform.os }}
steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.platform.target }}
- name: Install dependencies (Linux)
if: matrix.platform.platform == 'linux'
run: |
sudo apt-get update
sudo apt-get install -y \
make \
libgit2-dev \
build-essential \
pkg-config \
libbsd-dev \
libcap-dev \
libcups2-dev \
libgnutls28-dev \
libicu-dev \
libjansson-dev \
libkeyutils-dev \
libldap2-dev \
zlib1g-dev \
libpam0g-dev \
libacl1-dev \
libarchive-dev \
flex \
bison \
libntirpc-dev \
libtracker-sparql-3.0-dev \
libglib2.0-dev \
libdbus-1-dev \
libsasl2-dev \
libunistring-dev \
libdbus-1-dev \
cpanminus;
sudo cpanm Parse::Yapp::Driver
- name: Install dependencies (MacOS)
if: matrix.platform.platform == 'macos'
run: |
brew update
brew install \
bison \
cpanminus \
cups \
flex \
gettext \
gmp \
gnutls \
icu4c \
jansson \
libarchive \
libbsd \
libunistring \
libgit2 \
libtirpc \
openldap \
pkg-config \
zlib
brew link --force bison
brew link --force cups
brew link --force flex
brew link --force gettext
brew link --force gmp
brew link --force gnutls
brew link --force icu4c
brew link --force jansson
brew link --force libarchive
brew link --force libbsd
brew link --force libgit2
brew link --force libtirpc
brew link --force libunistring
brew link --force openldap
brew link --force zlib
cpanm Parse::Yapp::Driver
- name: Build release (MacOS Intel)
if: matrix.platform.target == 'x86_64-apple-darwin'
run: cargo build --release --no-default-features --features keyring --target ${{ matrix.platform.target }}
- name: Build release (others)
if: matrix.platform.target != 'x86_64-apple-darwin'
run: cargo build --release --features smb-vendored --target ${{ matrix.platform.target }}
- name: Build deb
if: matrix.platform.platform == 'linux'
run: |
cargo install cargo-deb
cargo deb --target ${{ matrix.platform.target }} --features smb-vendored
- name: Prepare artifact files (Posix)
if: matrix.platform.platform != 'windows'
run: |
mkdir -p .artifact
mv target/${{ matrix.platform.target }}/release/termscp .artifact/termscp
tar -czf .artifact/termscp-v${{ env.TERMSCP_VERSION }}-${{ matrix.platform.target }}.tar.gz -C .artifact termscp
ls -l .artifact/
- name: Upload artifact (Posix)
if: matrix.platform.platform != 'windows'
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
retention-days: 1
name: termscp-${{ matrix.platform.target }}
path: .artifact/termscp-v${{ env.TERMSCP_VERSION }}-${{ matrix.platform.target }}.tar.gz
- name: Upload artifact (Windows)
if: matrix.platform.platform == 'windows'
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
retention-days: 1
name: termscp-v${{ env.TERMSCP_VERSION }}-${{ matrix.platform.target }}
path: target/${{ matrix.platform.target }}/release/termscp.exe
- name: Upload artifact (Deb)
if: matrix.platform.platform == 'linux'
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
retention-days: 1
name: termscp-${{ matrix.platform.target }}-deb
path: target/debian/termscp_${{ env.TERMSCP_VERSION }}-1_${{ matrix.platform.debian_suffix }}.deb

View File

@@ -1,37 +0,0 @@
name: Coverage
on: [push, pull_request]
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: sudo apt update && sudo apt install -y libdbus-1-dev libssh2-1-dev libssl-dev
- name: Setup nightly toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
override: true
- name: Run tests (nightly)
uses: actions-rs/cargo@v1
with:
command: test
args: --no-default-features --features github-actions --no-fail-fast
env:
CARGO_INCREMENTAL: "0"
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
RUSTDOCFLAGS: "-Zprofile -Ccodegen-units=1 -Cinline-threshold=0 -Clink-dead-code -Coverflow-checks=off -Cpanic=abort -Zpanic_abort_tests"
- name: Coverage with grcov
id: coverage
uses: actions-rs/grcov@v0.1
- name: Coveralls
uses: coverallsapp/github-action@v1.1.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ${{ steps.coverage.outputs.report }}

View File

@@ -1,22 +0,0 @@
name: FreeBSD
on: [push, pull_request]
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: FreeBSD build
id: test
uses: vmactions/freebsd-vm@v0.1.4
with:
usesh: true
prepare: pkg install -y curl wget libssh gcc vim dbus pkgconf
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rustup.sh && \
chmod +x /tmp/rustup.sh && \
/tmp/rustup.sh -y
. $HOME/.cargo/env
cargo build --no-default-features
cargo test --no-default-features --verbose --features github-actions

23
.github/workflows/install.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: Install.sh
on:
push:
branches: [main]
tags:
- "v*"
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: sudo apt update && sudo apt install -y curl wget libsmbclient
- name: Install termscp from script
run: |
./install.sh -v=0.12.3 -f
which termscp || exit 1

View File

@@ -1,6 +1,14 @@
name: Linux
on: [push, pull_request]
on:
pull_request:
paths-ignore:
- "*.md"
- "./site/**/*"
push:
paths-ignore:
- "*.md"
- "./site/**/*"
env:
CARGO_TERM_COLOR: always
@@ -12,11 +20,10 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: sudo apt update && sudo apt install -y libdbus-1-dev libssh2-1-dev libssl-dev
- uses: actions-rs/toolchain@v1
run: sudo apt update && sudo apt install -y libdbus-1-dev libsmbclient-dev
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
override: true
components: rustfmt, clippy
- name: Run tests
uses: actions-rs/cargo@v1

View File

@@ -1,6 +1,14 @@
name: MacOS
on: [push, pull_request]
on:
pull_request:
paths-ignore:
- "*.md"
- "./site/**/*"
push:
paths-ignore:
- "*.md"
- "./site/**/*"
env:
CARGO_TERM_COLOR: always
@@ -8,9 +16,19 @@ env:
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: rustfmt, clippy
- name: Install dependencies
run: |
brew update
brew install \
pkg-config \
samba
brew link --force samba
- name: Build
run: cargo build
- name: Run tests

24
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v4.1.1
with:
days-before-issue-stale: 30
days-before-issue-close: 7
stale-issue-label: "stale"
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale."
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}
exempt-issue-labels: "backlog"
exempt-all-milestones: true

44
.github/workflows/website.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
# Simple workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]
paths:
- ".github/workflows/website.yml"
- "site/**"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
# Single deploy job since we're just deploying
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: "./site/"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

View File

@@ -1,16 +1,28 @@
name: Windows
on: [push, pull_request]
on:
pull_request:
paths-ignore:
- "*.md"
- "./site/**/*"
push:
paths-ignore:
- "*.md"
- "./site/**/*"
env:
CARGO_TERM_COLOR: always
jobs:
build:
runs-on: windows-2019
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
components: rustfmt, clippy
- name: Build
run: cargo build
- name: Run tests

1
.gitignore vendored
View File

@@ -23,3 +23,4 @@ dist/pkgs/arch/*.tar.gz
.DS_Store
dist/pkgs/
dist/build/macos/openssl/

View File

@@ -1,6 +1,26 @@
# Changelog
- [Changelog](#changelog)
- [0.19.0](#0190)
- [0.18.0](#0180)
- [0.17.0](#0170)
- [0.16.1](#0161)
- [0.16.0](#0160)
- [0.15.0](#0150)
- [0.14.0](#0140)
- [0.13.0](#0130)
- [0.12.3](#0123)
- [0.12.2](#0122)
- [0.12.1](#0121)
- [0.12.0](#0120)
- [0.11.3](#0113)
- [0.11.2](#0112)
- [0.11.1](#0111)
- [0.11.0](#0110)
- [0.10.0](#0100)
- [0.9.0](#090)
- [0.8.2](#082)
- [0.8.1](#081)
- [0.8.0](#080)
- [0.7.0](#070)
- [0.6.1](#061)
@@ -22,6 +42,316 @@
---
## 0.19.0
Released on 11/11/2025
- [Issue 297](https://github.com/veeso/termscp/issues/297): Added `<CTRL+S>` keybinding to get the total size of selected paths.
- [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 335](https://github.com/veeso/termscp/issues/335): Changed file overwrite behaviour
- Now the user can choose for each file whether to overwrite, skip or overwrite all/skip all.
- [Issue 354](https://github.com/veeso/termscp/issues/354):
- Removed error popup message if failed to check for updates.
- Prevent long timeouts when checking for updates if the network is down or the DNS is not working.
- [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.
- [Issue 361](https://github.com/veeso/termscp/issues/361): Report a message while calculating total size of files to transfer.
## 0.18.0
Released on 11/11/2025
- 🐚 An **Embedded shell for termscp**:
- [Issue 340](https://github.com/veeso/termscp/issues/340): Replaced the `Exec` popup with a **fully functional terminal emulator** embedded thanks to [A-Kenji's tui-term](https://github.com/a-kenji/tui-term).
- Command History
- Support for `cd` and `exit` commands as well.
- Exit just closes the terminal emulator.
- [Issue 345](https://github.com/veeso/termscp/issues/345): Default keys are used from `~/.ssh` directory if no keys are resolved for the host.
- **Updated dependencies** and updated the Rust edition to `2024`
## 0.17.0
Released on 24/03/2025
- **Queuing transfers**:
- the logic of selecting files has been extended!
- From now on selecting file will put the files into a **transfer queue**, which is shown on the bottom panel.
- When a file is selected the file is added to the queue with a destination path, which is the **current other explorer path at the moment of selection.**
- It is possible to navigate to the transfer queue by using `P` and pressing `ENTER` or `DELETE` on a file will remove it from the transfer queue.
- Other commands will work as well on the transfer queue, like `COPY`, `MOVE`, `DELETE`, `RENAME`.
- [issue 308](https://github.com/veeso/termscp/issues/308): added `--wno-keyring` flag to disable keyring
- [issue 316](https://github.com/veeso/termscp/issues/316): Local directory path is not switching to what's specified in the bookmark. Now the local directory path is correctly set following this hierarchy:
1. Local directory path specified for the host bridge
2. Local directory path specified in the bookmark
3. Working directory
- [issue 317](https://github.com/veeso/termscp/issues/317): the return value of `--version` should be `0`
- [issue 319](https://github.com/veeso/termscp/issues/319): fixed a crash when the local directory specified in the auth form does not exist
- [issue 327](https://github.com/veeso/termscp/issues/327): fixed a panic when trying to go up from local directory on localhost in the auth form
- [issue 330](https://github.com/veeso/termscp/issues/330): add suppaftp/pavao/kube to allowed logs
- Dependencies:
- `argh` to `0.1.13`
- `bytesize` to `2`
- `dirs` to `6`
- `magic-crypt` to `4`
- `notify` to `8`
- `ssh2-config` to `0.4`
- `remotefs-ssh` to `0.6`
- `rust` edition to `2024`
## 0.16.1
Released on 12/11/2024
- Just fixed this: e45c3d5b4ef64653e5b6cc4f3703e3b67514306d
- `fix: gg rust 1.82 for introducing a nice breaking change in config which was not mentioned in changelog`
## 0.16.0
Released on 14/10/2024
- [**Multi Host support**](https://github.com/veeso/termscp/issues/285):
- Now it is possible to work on two different remotes `remote A -> remote B` instead of just `localhost -> remote`
- Cli arguments now accept an additional `remote-args` for the left panel.
- For more details read this issue <https://github.com/veeso/termscp/issues/285>.
- Change between auth forms with `<BACKTAB>`
- Bookmarks are automatically loaded into the last auth form.
- [Issue 289](https://github.com/veeso/termscp/issues/289): Use `uzers` instead of the dead package `users` which has several vulnerabilities
- [Issue 290](https://github.com/veeso/termscp/issues/290): Password prompt was broken
- [Issue 298](https://github.com/veeso/termscp/issues/298): tuirealm 2.x
- Fixed some performance issues where sometimes the app froze for a couple of seconds, thanks to this <https://github.com/veeso/tui-realm/pull/78>.
- [Issue 292](https://github.com/veeso/termscp/issues/292): New version alert was not displayed due to a semver regex issue.
- [Issue 291](https://github.com/veeso/termscp/issues/291): Show `..` directory before all the others in the explorer. If you click on it you'll go the parent directory (same as pressing `<U>`). No, you can't select it for transfers and it's actually been implemented in the worse way possible, because this little change would require a huge refactoring of the explorer component. I promise I will do it one day, but I dunno when.
- Logging: filter out messages not related to termscp or remotefs
## 0.15.0
Released on 03/10/2024
- [Issue 249](https://github.com/veeso/termscp/issues/249): The old *find* command has been replaced with a brand new explorer with support to 🪄 **Fuzzy search** 🪄. The command is still `<F>`.
- [Issue 283](https://github.com/veeso/termscp/issues/283): **Find command can now be cancelled** by pressing `<CTRL+C>`. While scanning the directory it will also display the current progress.
- [Issue 268](https://github.com/veeso/termscp/issues/268): 📦 **Pods and container explorer** 🐳 for Kube protocol.
- BREAKING ‼️ Kube address argument has changed to `namespace[@<cluster_url>][$<path>]`
- Pod and container argumets have been removed; from now on you will connect with the following syntax to the provided namespace: `/pod-name/container-name/path/to/file`
- [Issue 279](https://github.com/veeso/termscp/issues/279): do not clear screen
- [Issue 277](https://github.com/veeso/termscp/issues/277): Fix a bug in the configuration page, which caused being stuck if the added SSH key was empty
- [Issue 272](https://github.com/veeso/termscp/issues/272): `isolated-tests` feature to run tests for releasing on distributions which run in isolated environments
- [Issue 280](https://github.com/veeso/termscp/issues/280): Autocompletion when pressing `<TAB>` on the `Go to` popup.
## 0.14.0
Released on 17/07/2024
- [Issue 226](https://github.com/veeso/termscp/issues/226): Use ssh-agent
- [Issue 241](https://github.com/veeso/termscp/issues/241): Jump to next entry after select
- [Issue 242](https://github.com/veeso/termscp/issues/242): Added `Kube` protocol support
- [Issue 255](https://github.com/veeso/termscp/issues/255): New keybindings `Alt + A` to deselect all files
- [Issue 256](https://github.com/veeso/termscp/issues/256): Filter files in current folder. You can now filter files by pressing `/`. Both wildmatch and regex are accepted to filter files.
- [Issue 257](https://github.com/veeso/termscp/issues/257): CLI remote args cannot handle '@' in the username
## 0.13.0
Released on 03/03/2024
- Added CLI subcommands
- Changed `-t` to `theme`
- Changed `-u` to `update`
- Changed `-c` to `config`
- Introduced support for [WebDAV](https://www.rfc-editor.org/rfc/rfc4918)
- It is now possible also to connect directly to WebDAV server with the syntax `http(s)://username:password@google.com`
- Bugfix:
- [Issue 232](https://github.com/veeso/termscp/issues/232): AWS S3 wasn't working anymore due to rust-s3 outdate
- Dependencies:
- Added `remotefs-webdav 0.1.1`
## 0.12.3
Released on 06/10/2023
- Dropped ratatui support, reverted to tui-realm 1.8
## 0.12.2
Released on 01/10/2023
- [Issue 205](https://github.com/veeso/termscp/issues/205): Allow windows build without SMB support
- [Issue 215](https://github.com/veeso/termscp/issues/215): termscp not respecting port in SSH config. The port specified for the host in the SSH configuration wasn't evaluated.
- [Issue 213](https://github.com/veeso/termscp/issues/215): termscp panicks if the terminal window is too small
## 0.12.1
Released on 06/07/2023
- [Issue 169](https://github.com/veeso/termscp/issues/169): Local working directory can now be specified in connection form and be saved into bookmarks.
- [Issue 188](https://github.com/veeso/termscp/issues/188): The breadcrumbs path is not fallbacked after a failed enter into the directory
- SMB support is now a feature (you can build rust without default features to disable smb).
- If SSH connection timeout is 0, the connection won't timeout.
## 0.12.0
Released on 16/05/2023
- **Change file permissions**: you can now change file permissions easily with the permissions popup pressing `Z` in the explorer.
- [Issue 172](https://github.com/veeso/termscp/issues/172)
- **SMB protocol**: Support for SMB protocol has been added thanks to the [remotefs-smb](https://github.com/veeso/remotefs-rs-smb) library and the [pavao](https://github.com/veeso/pavao) project. You may notice that the interface is quiet different between Windows and Linux/MacOs/BSD due to the fact that SMB is natively supported on Windows systems.
- [Issue 182](https://github.com/veeso/termscp/issues/182)
- [Issue 153](https://github.com/veeso/termscp/issues/153): show a loading message when loading directory's content
- [Issue 176](https://github.com/veeso/termscp/issues/176): debug log is now written to CACHE_DIR
- [Issue 173](https://github.com/veeso/termscp/issues/173): allow unknown fields in ssh2 configuration file
- [Issue 175](https://github.com/veeso/termscp/issues/175): don't prompt for password if a ssh key is set for that host
- Fixed an issue that didn't use the `User` specified in ssh2-config
## 0.11.3
Released on 19/04/2023
- [Issue 166](https://github.com/veeso/termscp/issues/166): fixed SCP relative paths on Windows
## 0.11.2
Released on 18/04/2023
- [Issue 154](https://github.com/veeso/termscp/issues/154): fixed SCP relative paths on Windows
## 0.11.1
Released on 07/03/2022
- [Issue 150](https://github.com/veeso/termscp/issues/150)
- fixed config directory not being created
- before setting default ssh config path; check wheter it actually exists
- Security:
- removed `remove_dir_all` crate with `tempfile 3.4`
- Dependencies:
- Bump `ssh2-config` to `0.1.6`
## 0.11.0
Released on 20/02/2023
> 🦥 The lazy update
- **Transfers optimized**:
- If local/remote file have the same "last modification time" (`mtime`), the file is not transferred
- When the file is exchanged, all times attributes are set (if supported by the protocol)
- **Default ssh config path**:
- SSH configuration path is now `~/.ssh/config` by default
- Added ARM64 Linux builds
- **Bugfix**:
- Fixed [Issue 126](https://github.com/veeso/termscp/issues/126)
- Fixed [Issue 141](https://github.com/veeso/termscp/issues/141)
- Dependencies:
- Bump `remotefs-ssh` to `0.1.3`
- Bump `self_update` to `0.35`
- Bump `ssh2-config` to `0.1.4`
- Bump `toml` to `0.7`
## 0.10.0
Released on 15/10/2022
> ⭐ 500 stars update ⭐
> Thank you for supporting termscp and make it reaching 500 stars on Github
- **Changed keybindings for BACKTAB**: backtab will now change the explorer tab
- To active the LOG PANEL, use `P`
- **Yes/No dialogs** are now answerable by pressing `Y` or `N` on your keyboard ([Issue 121](https://github.com/veeso/termscp/issues/121))
- **Use ssh2 config IdentityFile** as fallback for key based authentication
- **Bugfix**
- Fixed [Issue 122](https://github.com/veeso/termscp/issues/122)
- Fixed version comparison when going above 0.9
- Dependencies:
- Bump `argh` to `0.1.9`
- Bump `chrono` to `0.4.22`
- Bump `keyring` to `1.2.0`
- Bump `notify-rust` to `4.5.10`
- Bump `open` to `3.0.3`
- Bump `rpassword` to `7.0.0`
- Changed `regex` to `lazy-regex 2.3.0`
- Bump `remotefs-ftp` to `0.1.2`
- Bump `remotefs-ssh` to `0.1.2`
- Bump `self_update` to `0.32`
- Bump `ssh2-config` to `0.1.3`
- Bump `tuirealm` to `1.8.0`
- Bump `tui-realm-stdlib` to `1.1.7`
- Bump `unicode-width` to `0.1.10`
- Added `version-compare 0.1.0`
- Bump `whoami` to `1.2.3`
- Bump `wildmatch` to `2.1.1`
- Removed libssl dependency
## 0.9.0
Released on 18/06/2022
> 🏖️ Tenerife Update 🍹
- **Bookmark name as hostname for CLI arguments**
- It is now possible to provide the name of the bookmark you want to connect to, instead of the address in command line arguments
To do so it is enough to run termscp as follows:
```sh
termscp -b <bookmark-name>
```
If the password is stored in the bookmark, it will be used, otherwise you will be prompted to type the password in.
- **Remote directory path in authentication form and in bookmarks parameters**:
- It is now possible to configure the directory path you want to enter when you connect to the remote host from the authentication form
- This parameter can be stored into bookmarks as you already do with the other parameters
- You can find this field scrolling down in the authentication form
- **File system watcher**:
- It is now possible to synchronize changes from a local path to the remote host
- Press `<T>` to start synchronizing changes from the selected directory/file to the remote directory
- The changes will be automatically applied to the remote host with a maximum delay of 5 seconds
- These changes are (if possible) applied: file removed, file changed, file renamed
- Press `<CTRL+T>` to show all the currently synchronized files
- **Enhancements**:
- Improved s3 auth form scrolling
- **Bugfix**:
- Fixed SSH key list showing `{hostname} at {username}` instead of `{username} at {hostname}`
- Dependencies:
- Updated `edit` to `0.1.4`
- Updated `log` to `0.4.17`
- Updated `magic-crypt` to `3.1.10`
- Updated `open` to `2.1.3`
- Updated `regex` to `1.5.6`
- Updated `rpassword` to `6.0.1`
- Updated `self_update` to `0.30.0`
- Updated `simplelog` to `0.12.0`
- Updated `toml` to `0.5.9`
- Updated `tui-realm` to `1.6.0`
## 0.8.2
Released on 26/04/2022
- **Enhancements**
- Write exitcode to log when termscp terminates
- Bugfix:
- [Issue 104](https://github.com/veeso/termscp/issues/104): Fixed termscp panics when displaying long non-ascii filenames
## 0.8.1
Released on 22/03/2022
- **Added support for S3 compatible backends**
- Changed `AWS S3` to `S3` in ui
- Added new `endpoint` and `new-path-style` to s3 connection parameters
- Bugfix:
- [Issue 92](https://github.com/veeso/termscp/issues/92): updated ssh2-config to 0.1.3, which solves this issue.
- [Issue 99](https://github.com/veeso/termscp/issues/99): Fixed AltGr characters not allowed in auth form
- Dependencies:
- Updated `keyring` to `1.1.2`
- Updated `notify-rust` to `4.5.6`
- Updated `open` to `2.0.3`
- Updated `rand` to `0.8.5`
- Updated `regex` to `1.5.5`
- Updated `remotefs-rs-aws-s3` to `0.2.0`
- Updated `tui-realm` to `1.5.0`
- Updated `tui-realm-stdlib` to `1.1.6`
## 0.8.0
Released on 06/01/2022

View File

@@ -2,75 +2,131 @@
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
Examples of behavior that contributes to a positive environment for our
community include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior by participants include:
Examples of unacceptable behavior include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
professional setting
## Our Responsibilities
## Enforcement Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official email address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at christian.visintin1997@gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
reported to the community leaders responsible for enforcement at
[INSERT CONTACT METHOD].
All complaints will be reviewed and investigated promptly and fairly.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
<https://www.contributor-covenant.org/faq>
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -1,7 +1,7 @@
# Contributing
Before contributing to this repository, please first discuss the change you wish to make via issue of this repository before making a change.
Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in all your interactions with the project.
Please note we have a [code of conduct](CODE_OF_CONDUCT.md). Please follow it in all your interactions with the project.
- [Contributing](#contributing)
- [Project mission](#project-mission)
@@ -20,9 +20,13 @@ Please note we have a [code of conduct](CODE_OF_CONDUCT.md), please follow it in
## Project mission
termscp was born because, as a terminal lover and Linux user, I wanted something like WinSCP on Linux and on terminal. I my previous job I used SFTP/SCP pratically everyday and that made me to desire an application like termscp so much, that eventually I started to work on it in the spare time. I saw there was a very cool library to create terminal user interface (`tui-rs`), so I started to code it. I wrote termscp as an experiment, I designed kinda nothing at the time. I just said
termscp was born because, as a terminal lover and Linux user, I wanted something like WinSCP on Linux and on terminal. At my previous job, I used SFTP/SCP practically everyday and that made me desire an application like termscp so much that eventually I started to work on it in my spare time.
> Ok, there must be a `FileTransfer` trait somehow, I'll have more views, so I'll use something like Android activities, and there must be a module to interact with the local host".
I saw there was a very cool library to create terminal user interfaces (`tui-rs`, now `ratatui`), so I started to code it.
I wrote termscp as an experiment. I didn't design anything at the time. I just said,
> "Ok, there must be a FileTransfer trait somehow. I'll have more views, so I'll use something like Android activities, and there must be a module to interact with the local host."
And so in december 2020 I had the first version of termscp running and it worked, but was very simple, raw and minimal.
A lot of things have changed since them, both the features the project provides and my personal view of this project.
@@ -95,8 +99,6 @@ Said so, follow these steps:
- Open an issue using the `feature request` template describing with accuracy your suggestion
- Wait for the maintainer feedback on your idea
If you want to implement the feature by yourself and your suggestion gets approved, start writing the code. Remember that on [docs.rs](https://docs.rs/termscp) there is the documentation for the project. Open a PR related to your issue. See [Pull request process for more details](#pull-request-process)
It is very important to follow these steps, since it will prevent you from working on a feature that will be rejected and trust me, none of us wants to deal with this situation.
Always mind that your suggestion, may be rejected: I'll always provide a feedback on the reasons that brought me to reject your feature, just try not to get mad about that.

5732
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,17 @@
[package]
authors = ["Christian Visintin"]
authors = ["Christian Visintin <christian.visintin@veeso.dev>"]
categories = ["command-line-utilities"]
description = "termscp is a feature rich terminal file transfer and explorer with support for SCP/SFTP/FTP/S3"
documentation = "https://docs.rs/termscp"
edition = "2021"
homepage = "https://veeso.github.io/termscp/"
include = ["src/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
keywords = ["scp-client", "sftp-client", "ftp-client", "winscp", "command-line-utility"]
description = "termscp is a feature rich terminal file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/WebDAV"
edition = "2024"
homepage = "https://termscp.veeso.dev"
include = ["src/**/*", "build.rs", "LICENSE", "README.md", "CHANGELOG.md"]
keywords = ["terminal", "ftp", "scp", "sftp", "tui"]
license = "MIT"
name = "termscp"
readme = "README.md"
repository = "https://github.com/veeso/termscp"
version = "0.8.0"
version = "0.19.0"
rust-version = "1.88.0"
[package.metadata.rpm]
package = "termscp"
@@ -23,8 +23,8 @@ buildflags = ["--release"]
termscp = { path = "/usr/bin/termscp" }
[package.metadata.deb]
maintainer = "Christian Visintin <christian.visintin1997@gmail.com>"
copyright = "2022, Christian Visintin <christian.visintin1997@gmail.com>"
maintainer = "Christian Visintin <christian.visintin@veeso.dev>"
copyright = "2025, Christian Visintin <christian.visintin@veeso.dev>"
extended-description-file = "docs/misc/README.deb.txt"
[[bin]]
@@ -32,51 +32,93 @@ name = "termscp"
path = "src/main.rs"
[dependencies]
argh = "0.1.7"
bitflags = "1.3.2"
bytesize = "1.1.0"
chrono = "0.4.19"
content_inspector = "0.2.4"
dirs = "4.0.0"
edit = "0.1.3"
hostname = "0.3.1"
keyring = { version = "1.0.0", optional = true }
lazy_static = "1.4.0"
log = "0.4.14"
magic-crypt = "3.1.9"
notify-rust = { version = "4.5.5", default-features = false, features = [ "d" ] }
open = "2.0.2"
rand = "0.8.4"
regex = "1.5.4"
remotefs = "^0.2.0"
remotefs-aws-s3 = "^0.1.0"
remotefs-ftp = { version = "^0.1.0", features = [ "secure" ] }
remotefs-ssh = "^0.1.0"
rpassword = "5.0.1"
self_update = { version = "0.28.0", features = [ "archive-tar", "archive-zip", "compression-flate2", "compression-zip-deflate" ] }
serde = { version = "^1.0.0", features = [ "derive" ] }
simplelog = "0.11.1"
tempfile = "3.2.0"
thiserror = "^1.0.0"
toml = "0.5.8"
tui-realm-stdlib = "1.1.5"
tuirealm = "1.4.2"
unicode-width = "0.1.8"
whoami = "1.2.1"
wildmatch = "2.1.0"
argh = "^0.1"
bitflags = "^2"
bytesize = "^2"
chrono = "^0.4"
content_inspector = "^0.2"
dirs = "^6"
edit = "^0.1"
filetime = "^0.2"
hostname = "^0.4"
keyring = { version = "^3", features = [
"apple-native",
"windows-native",
"sync-secret-service",
"vendored",
] }
lazy-regex = "^3"
lazy_static = "^1"
log = "^0.4"
magic-crypt = "4"
notify = "8"
notify-rust = { version = "^4", default-features = false, features = ["d"] }
nucleo = "0.5"
open = "^5.0"
rand = "^0.9"
regex = "^1"
remotefs = "^0.3"
remotefs-aws-s3 = "0.4"
remotefs-kube = "0.4"
remotefs-smb = { version = "^0.3", optional = true }
remotefs-webdav = "^0.2"
rpassword = "^7"
self_update = { version = "^0.42", default-features = false, features = [
"rustls",
"archive-tar",
"archive-zip",
"compression-flate2",
"compression-zip-deflate",
] }
serde = { version = "^1", features = ["derive"] }
shellexpand = "3"
simplelog = "^0.12"
ssh2-config = "^0.6"
tempfile = "3"
thiserror = "2"
tokio = { version = "1", features = ["rt"] }
toml = "^0.9"
tui-realm-stdlib = "3"
tuirealm = "3"
tui-term = "0.2"
unicode-width = "^0.2"
version-compare = "^0.2"
whoami = "^1.6"
wildmatch = "^2"
[target."cfg(target_family = \"unix\")".dependencies]
remotefs-ftp = { version = "^0.3", features = [
"native-tls-vendored",
"native-tls",
] }
remotefs-ssh = { version = "^0.7", default-features = false, features = [
"find",
"libssh-vendored",
] }
uzers = "0.12"
[target."cfg(target_family = \"windows\")".dependencies]
remotefs-ftp = { version = "^0.3", features = ["native-tls"] }
remotefs-ssh = { version = "^0.7" }
[dev-dependencies]
pretty_assertions = "0.7.2"
serial_test = "^0.5.1"
pretty_assertions = "^1"
serial_test = "^3"
[build-dependencies]
cfg_aliases = "0.2"
vergen-git2 = { version = "1", features = ["build", "cargo", "rustc", "si"] }
[features]
default = [ "with-keyring" ]
github-actions = [ ]
with-keyring = [ "keyring" ]
[target."cfg(target_family = \"unix\")"]
[target."cfg(target_family = \"unix\")".dependencies]
users = "0.11.0"
default = ["smb", "keyring"]
github-actions = []
isolated-tests = []
keyring = []
smb = ["dep:remotefs-smb"]
smb-vendored = ["remotefs-smb/vendored"]
[profile.dev]
incremental = true
[profile.release]
strip = true

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 Christian Visintin
Copyright (c) 2020-2022 Christian Visintin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

103
README.md
View File

@@ -1,26 +1,34 @@
# termscp
<p align="center">
<img src="/assets/images/termscp.svg" width="256" height="256" />
<img src="/assets/images/termscp.svg" alt="termscp logo" width="256" height="256" />
</p>
<p align="center">~ A feature rich terminal file transfer ~</p>
<p align="center">
<a href="https://veeso.github.io/termscp/" target="_blank">Website</a>
<a href="https://termscp.veeso.dev" target="_blank">Website</a>
·
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Installation</a>
<a href="https://termscp.veeso.dev/get-started.html" target="_blank">Installation</a>
·
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">User manual</a>
<a href="https://termscp.veeso.dev/user-manual.html" target="_blank">User manual</a>
</p>
<p align="center">
<a href="https://github.com/veeso/termscp"
><img
height="20"
src="/assets/images/flags/us.png"
src="/assets/images/flags/gb.png"
alt="English"
/></a>
&nbsp;
<a
href="/docs/pt-BR/README.md"
><img
height="20"
src="/assets/images/flags/br.png"
alt="Brazilian Portuguese"
/></a>
&nbsp;
<a
href="/docs/de/README.md"
><img
@@ -62,8 +70,8 @@
/></a>
</p>
<p align="center">Developed by <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
<p align="center">Current version: 0.8.0 (06/01/2022)</p>
<p align="center">Developed by <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Current version: 0.19.0 11/11/2025</p>
<p align="center">
<a href="https://opensource.org/licenses/MIT"
@@ -73,7 +81,7 @@
/></a>
<a href="https://github.com/veeso/termscp/stargazers"
><img
src="https://img.shields.io/github/stars/veeso/termscp.svg"
src="https://img.shields.io/github/stars/veeso/termscp?style=flat"
alt="Repo stars"
/></a>
<a href="https://crates.io/crates/termscp"
@@ -108,28 +116,13 @@
src="https://github.com/veeso/termscp/workflows/Windows/badge.svg"
alt="Windows CI"
/></a>
<a href="https://github.com/veeso/termscp/actions"
><img
src="https://github.com/veeso/termscp/workflows/FreeBSD/badge.svg"
alt="FreeBSD CI"
/></a>
<a href="https://coveralls.io/github/veeso/termscp"
><img
src="https://coveralls.io/repos/github/veeso/termscp/badge.svg"
alt="Coveralls"
/></a>
<a href="https://docs.rs/termscp"
><img
src="https://docs.rs/termscp/badge.svg"
alt="Docs"
/></a>
</p>
---
## About termscp 🖥
Termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/S3. So basically is a terminal utility with an TUI to connect to a remote server to retrieve and upload files and to interact with the local file system. It is **Linux**, **MacOS**, **FreeBSD** and **Windows** compatible.
Termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/Kube/S3/WebDAV. So basically is a terminal utility with an TUI to connect to a remote server to retrieve and upload files and to interact with the local file system. It is **Linux**, **MacOS**, **FreeBSD**, **NetBSD** and **Windows** compatible.
![Explorer](assets/images/explorer.gif)
@@ -141,13 +134,17 @@ Termscp is a feature rich terminal file transfer and explorer, with support for
- **SFTP**
- **SCP**
- **FTP** and **FTPS**
- **Aws S3**
- **Kube**
- **S3**
- **SMB**
- **WebDAV**
- 🖥 Explore and operate on the remote and on the local machine file system with a handy UI
- Create, remove, rename, search, view and edit files
- ⭐ Connect to your favourite hosts through built-in bookmarks and recent connections
- 📝 View and edit files with your favourite applications
- 💁 SFTP/SCP authentication with SSH keys and username/password
- 🐧 Compatible with Windows, Linux, FreeBSD and MacOS
- 🐧 Compatible with Windows, Linux, FreeBSD, NetBSD and MacOS
- 🐚 Embedded terminal for executing commands on the system.
- 🎨 Make it yours!
- Themes
- Custom file explorer format
@@ -155,6 +152,7 @@ Termscp is a feature rich terminal file transfer and explorer, with support for
- Customizable file sorting
- and many other parameters...
- 📫 Get notified via Desktop Notifications when a large file has been transferred
- 🔭 Keep file changes synchronized with the remote host
- 🔐 Save your password in your operating system key vault
- 🦀 Rust-powered
- 👀 Developed keeping an eye on performance
@@ -173,26 +171,40 @@ If you are a Linux, a FreeBSD or a MacOS user this simple shell script will inst
curl --proto '=https' --tlsv1.2 -sSLf "https://git.io/JBhDb" | sh
```
> ❗ MacOs installation requires [Homebrew](https://brew.sh/), otherwise the Rust compiler will be installed
while if you're a Windows user, you can install termscp with [Chocolatey](https://chocolatey.org/):
```sh
```ps
choco install termscp
```
For more information or other platforms, please visit [veeso.github.io](https://veeso.github.io/termscp/#get-started) to view all installation methods.
NetBSD users can install termscp from the official repositories.
```sh
pkgin install termscp
```
Arch Linux users can install termscp from the official repositories.
```sh
pacman -S termscp
```
For more information or other platforms, please visit [termscp.veeso.dev](https://termscp.veeso.dev/get-started.html) to view all installation methods.
⚠️ If you're looking on how to update termscp just run termscp from CLI with: `(sudo) termscp --update` ⚠️
### Requirements ❗
- **Linux** users:
- libssh
- libdbus-1
- pkg-config
- **FreeBSD** users:
- libssh
- libsmbclient
- **FreeBSD** or, **NetBSD** users:
- dbus
- pkgconf
- libsmbclient
### Optional Requirements ✔️
@@ -223,34 +235,15 @@ You can make a donation with one of these platforms:
---
## User manual and Documentation 📚
## User manual 📚
The user manual can be found on the [termscp's website](https://veeso.github.io/termscp/#user-manual) or on [Github](docs/man.md).
The developer documentation can be found on Rust Docs at <https://docs.rs/termscp>
The user manual can be found on the [termscp's website](https://termscp.veeso.dev/user-manual.html) or on [Github](docs/man.md).
---
## Upcoming Features 🧪
For **2022** there will be two major updates during the year.
Planned for *🍓 Spring update 2022 🌹*:
- **File system watcher 🔭**: The feature consists in the possibility to track some files in order to automatically sync them with remote host. For the implementation [notify](https://github.com/notify-rs/notify) will be used.
Planned for *future updates ⏲️*:
- **Translations 🌐**: The feature consists in the possibility for the user to install the language pack for the language he prefers in order to replace the default English interface. The following language will be provided along to English:
- 🇨🇳 Chinese
- 🇫🇷 French
- 🇩🇪 German
- 🇮🇹 Italian
- 🇳🇱 Dutch
- 🇪🇸 Spanish
- **Configuration profile for bookmarks 📚**: Basically this feature adds the possibility to have a specific setup for a certain host, instead of having only one global configuration. (Maybe will be postponed to spring 2022).
Along to new features, termscp developments is now focused on UX and performance improvements, so if you have any suggestion, feel free to open an issue.
See [Milestones](https://github.com/veeso/termscp/milestones)
---
@@ -279,11 +272,13 @@ termscp is powered by these awesome projects:
- [crossterm](https://github.com/crossterm-rs/crossterm)
- [edit](https://github.com/milkey-mouse/edit)
- [keyring-rs](https://github.com/hwchen/keyring-rs)
- [kube](https://github.com/kube-rs/kube)
- [open-rs](https://github.com/Byron/open-rs)
- [pavao](https://github.com/veeso/pavao)
- [remotefs](https://github.com/veeso/remotefs-rs)
- [rpassword](https://github.com/conradkleinespel/rpassword)
- [self_update](https://github.com/jaemk/self_update)
- [tui-rs](https://github.com/fdehau/tui-rs)
- [ratatui](https://github.com/ratatui-org/ratatui)
- [tui-realm](https://github.com/veeso/tui-realm)
- [whoami](https://github.com/libcala/whoami)
- [wildmatch](https://github.com/becheran/wildmatch)

BIN
assets/images/flags/gb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1002 B

33
build.rs Normal file
View File

@@ -0,0 +1,33 @@
use cfg_aliases::cfg_aliases;
use vergen_git2::{BuildBuilder, CargoBuilder, Emitter, Git2Builder, RustcBuilder, SysinfoBuilder};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Setup cfg aliases
cfg_aliases! {
// Platforms
macos: { target_os = "macos" },
linux: { target_os = "linux" },
posix: { target_family = "unix" },
win: { target_family = "windows" },
// exclusive features
smb: { feature = "smb" },
smb_unix: { all(unix, feature = "smb") },
smb_windows: { all(windows, feature = "smb") }
}
let build = BuildBuilder::all_build()?;
let cargo = CargoBuilder::all_cargo()?;
let git2 = Git2Builder::all_git()?;
let rustc = RustcBuilder::all_rustc()?;
let si = SysinfoBuilder::all_sysinfo()?;
Emitter::default()
.add_instructions(&build)?
.add_instructions(&cargo)?
.add_instructions(&git2)?
.add_instructions(&rustc)?
.add_instructions(&si)?
.emit()?;
Ok(())
}

26
dist/build/aarch64_centos7/Dockerfile vendored Normal file
View File

@@ -0,0 +1,26 @@
FROM centos:centos7 as builder
WORKDIR /usr/src/
# Install dependencies
RUN yum -y install \
git \
gcc \
pkgconfig \
gcc \
make \
dbus-devel \
libsmbclient-devel \
bash \
rpm-build
# Install rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rust.sh && \
chmod +x /tmp/rust.sh && \
/tmp/rust.sh -y
# Clone repository
RUN git clone https://github.com/veeso/termscp.git
# Set workdir to termscp
WORKDIR /usr/src/termscp/
# Install cargo rpm
RUN source $HOME/.cargo/env && cargo install cargo-rpm
ENTRYPOINT ["tail", "-f", "/dev/null"]

51
dist/build/aarch64_debian10/Dockerfile vendored Normal file
View File

@@ -0,0 +1,51 @@
FROM debian:buster
WORKDIR /usr/src/
# Install dependencies
RUN apt update && apt install -y \
git \
gcc \
pkg-config \
libdbus-1-dev \
build-essential \
libsmbclient-dev \
libgit2-dev \
build-essential \
pkg-config \
libbsd-dev \
libcap-dev \
libcups2-dev \
libgnutls28-dev \
libicu-dev \
libjansson-dev \
libkeyutils-dev \
libldap2-dev \
zlib1g-dev \
libpam0g-dev \
libacl1-dev \
libarchive-dev \
flex \
bison \
libntirpc-dev \
libtracker-sparql-3.0-dev \
libglib2.0-dev \
libdbus-1-dev \
libsasl2-dev \
libunistring-dev \
bash \
curl \
cpanminus && \
cpanm Parse::Yapp::Driver;
# Install rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rust.sh && \
chmod +x /tmp/rust.sh && \
/tmp/rust.sh -y
# Clone repository
RUN git clone https://github.com/veeso/termscp.git
# Set workdir to termscp
WORKDIR /usr/src/termscp/
# Install cargo deb
RUN . $HOME/.cargo/env && cargo install cargo-deb
ENTRYPOINT ["tail", "-f", "/dev/null"]

39
dist/build/docker.sh vendored
View File

@@ -1,39 +0,0 @@
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage: docker.sh <version>"
exit 1
fi
VERSION=$1
set -e # Don't fail
# Create pkgs directory
cd ..
PKGS_DIR=$(pwd)/pkgs
cd -
mkdir -p ${PKGS_DIR}/
# Build x86_64_deb
cd x86_64_debian9/
docker build --build-arg branch=${VERSION} --tag termscp-${VERSION}-x86_64_debian9 .
cd -
mkdir -p ${PKGS_DIR}/deb/
mkdir -p ${PKGS_DIR}/x86_64-unknown-linux-gnu/
CONTAINER_NAME=$(docker create termscp-${VERSION}-x86_64_debian9 /bin/bash)
docker cp ${CONTAINER_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}_amd64.deb ${PKGS_DIR}/deb/
docker cp ${CONTAINER_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/x86_64-unknown-linux-gnu/
# Make tar.gz
cd ${PKGS_DIR}/x86_64-unknown-linux-gnu/
tar cvzf termscp-v${VERSION}-x86_64-unknown-linux-gnu.tar.gz termscp
rm termscp
cd -
# Build x86_64_centos7
cd x86_64_centos7/
docker build --build-arg branch=${VERSION} --tag termscp-${VERSION}-x86_64_centos7 .
cd -
mkdir -p ${PKGS_DIR}/rpm/
CONTAINER_NAME=$(docker create termscp-${VERSION}-x86_64_centos7 /bin/bash)
docker cp ${CONTAINER_NAME}:/usr/src/termscp/target/release/rpmbuild/RPMS/x86_64/termscp-${VERSION}-1.el7.x86_64.rpm ${PKGS_DIR}/rpm/termscp-${VERSION}-1.x86_64.rpm
exit $?

View File

@@ -34,12 +34,12 @@ rm manifest
echo -e "name: \"termscp\"" > manifest
echo -e "version: $VERSION" >> manifest
echo -e "origin: veeso/termscp" >> manifest
echo -e "comment: \"A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3\"" >> manifest
echo -e "comment: \"A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/WebDAV\"" >> manifest
echo -e "desc: <<EOD\n\
A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/S3\n\
A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/WebDAV\n\
EOD\n\
arch: \"amd64\"\n\
www: \"https://veeso.github.io/termscp/\"\n\
www: \"https://termscp.veeso.dev/termscp/\"\n\
maintainer: \"christian.visintin1997@gmail.com\"\n\
prefix: \"/usr/local/bin\"\n\
deps: {\n\

52
dist/build/linux-aarch64.sh vendored Executable file
View File

@@ -0,0 +1,52 @@
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage: $0 <version> [branch] [--no-cache]"
exit 1
fi
VERSION=$1
if [ -z "$2" ]; then
BRANCH=$VERSION
else
BRANCH=$2
fi
CACHE=""
if [ "$3" == "--no-cache" ]; then
CACHE="--no-cache"
fi
# names
ARM64_DEB_NAME="termscp-arm64_deb"
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
set -e # Don't fail
# Create pkgs directory
cd ..
PKGS_DIR=$(pwd)/pkgs
cd -
mkdir -p ${PKGS_DIR}/
# Build aarch64_deb
cd aarch64_debian10/
docker buildx build --platform linux/arm64 $CACHE --build-arg branch=${BRANCH} --tag $ARM64_DEB_NAME .
cd -
mkdir -p ${PKGS_DIR}/deb/
mkdir -p ${PKGS_DIR}/aarch64-unknown-linux-gnu/
docker run --name "$ARM64_DEB_NAME" -d "$ARM64_DEB_NAME" || docker start "$ARM64_DEB_NAME"
docker exec -it "$ARM64_DEB_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH && cargo build --release --features smb-vendored && cargo deb"
docker cp ${ARM64_DEB_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}-1_arm64.deb ${PKGS_DIR}/deb/termscp_${VERSION}_arm64.deb
docker cp ${ARM64_DEB_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/aarch64-unknown-linux-gnu/
docker stop "$ARM64_DEB_NAME"
# Make tar.gz
cd ${PKGS_DIR}/aarch64-unknown-linux-gnu/
tar cvzf termscp-v${VERSION}-aarch64-unknown-linux-gnu.tar.gz termscp
echo "Sha256 (homebrew aarch64): $(sha256sum termscp-v${VERSION}-aarch64-unknown-linux-gnu.tar.gz)"
rm termscp
cd -
exit $?

50
dist/build/linux-x86_64.sh vendored Executable file
View File

@@ -0,0 +1,50 @@
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage: $0 <version> [branch] [--no-cache]"
exit 1
fi
VERSION=$1
if [ -z "$2" ]; then
BRANCH=$VERSION
else
BRANCH=$2
fi
CACHE=""
if [ "$3" == "--no-cache" ]; then
CACHE="--no-cache"
fi
# names
X86_64_DEB_NAME="termscp-x86_64_deb"
set -e # Don't fail
# Create pkgs directory
cd ..
PKGS_DIR=$(pwd)/pkgs
cd -
mkdir -p ${PKGS_DIR}/
# Build x86_64_deb
cd x86_64_debian12/
docker build $CACHE --build-arg branch=${BRANCH} --tag "$X86_64_DEB_NAME" .
cd -
mkdir -p ${PKGS_DIR}/deb/
mkdir -p ${PKGS_DIR}/x86_64-unknown-linux-gnu/
docker run --name "$X86_64_DEB_NAME" -d "$X86_64_DEB_NAME" || docker start "$X86_64_DEB_NAME"
docker exec -it "$X86_64_DEB_NAME" bash -c ". \$HOME/.cargo/env && git fetch origin && git checkout origin/$BRANCH && cargo build --release --features smb-vendored && cargo deb"
docker cp ${X86_64_DEB_NAME}:/usr/src/termscp/target/debian/termscp_${VERSION}-1_amd64.deb ${PKGS_DIR}/deb/termscp_${VERSION}_amd64.deb
docker cp ${X86_64_DEB_NAME}:/usr/src/termscp/target/release/termscp ${PKGS_DIR}/x86_64-unknown-linux-gnu/
docker stop "$X86_64_DEB_NAME"
# Make tar.gz
cd ${PKGS_DIR}/x86_64-unknown-linux-gnu/
tar cvzf termscp-v${VERSION}-x86_64-unknown-linux-gnu.tar.gz termscp
echo "Sha256 x86_64 (homebrew): $(sha256sum termscp-v${VERSION}-x86_64-unknown-linux-gnu.tar.gz)"
rm termscp
cd -
exit $?

96
dist/build/macos.sh vendored
View File

@@ -1,11 +1,72 @@
#!/bin/sh
make_pkg() {
ARCH=$1
VERSION=$2
TARGET_DIR="$3"
if [ -z "$TARGET_DIR" ]; then
TARGET_DIR=target/release/
fi
ROOT_DIR=$(pwd)
cd "$TARGET_DIR"
PKG="termscp-v${VERSION}-${ARCH}-apple-darwin.tar.gz"
tar czf "$PKG" termscp
HASH=$(sha256sum "$PKG")
mkdir -p "${ROOT_DIR}/dist/pkgs/macos/"
mv "$PKG" "${ROOT_DIR}/dist/pkgs/macos/$PKG"
cd -
echo "$HASH"
}
detect_platform() {
local platform
platform="$(uname -s | tr '[:upper:]' '[:lower:]')"
case "${platform}" in
linux) platform="linux" ;;
darwin) platform="macos" ;;
freebsd) platform="freebsd" ;;
esac
printf '%s' "${platform}"
}
detect_arch() {
local arch
arch="$(uname -m | tr '[:upper:]' '[:lower:]')"
case "${arch}" in
amd64) arch="x86_64" ;;
armv*) arch="arm" ;;
arm64) arch="aarch64" ;;
esac
# `uname -m` in some cases mis-reports 32-bit OS as 64-bit, so double check
if [ "${arch}" = "x86_64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then
arch="i686"
elif [ "${arch}" = "aarch64" ] && [ "$(getconf LONG_BIT)" -eq 32 ]; then
arch="arm"
fi
printf '%s' "${arch}"
}
if [ -z "$1" ]; then
echo "Usage: macos.sh <version>"
exit 1
fi
PLATFORM="$(detect_platform)"
ARCH="$(detect_arch)"
if [ "$PLATFORM" != "macos" ]; then
echo "macos build is only available on MacOs systems"
exit 1
fi
VERSION=$1
export BUILD_ROOT
BUILD_ROOT="$(pwd)/../../"
set -e # Don't fail
@@ -17,14 +78,33 @@ if [ ! -f Cargo.toml ]; then
exit 1
fi
# Build release
cargo build --release && cargo strip
# Build release (x86_64)
X86_TARGET=""
X86_TARGET_DIR=""
if [ "$ARCH" = "x86_64" ]; then
X86_TARGET="--target x86_64-apple-darwin"
X86_TARGET_DIR="target/x86_64-apple-darwin/release/"
fi
cargo build --release $X86_TARGET
# Make pkg
cd target/release/
PKG="termscp-v${VERSION}-x86_64-apple-darwin.tar.gz"
tar czf $PKG termscp
sha256sum $PKG
mkdir -p ../../dist/pkgs/macos/
mv $PKG ../../dist/pkgs/macos/$PKG
X86_64_HASH=$(make_pkg "x86_64" "$VERSION" $X86_TARGET_DIR)
RET_X86_64=$?
ARM64_TARGET=""
ARM64_TARGET_DIR=""
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
ARM64_TARGET="--target aarch64-apple-darwin"
ARM64_TARGET_DIR="target/aarch64-apple-darwin/release/"
fi
cd "$BUILD_ROOT"
# Build ARM64 pkg
cargo build --release $ARM64_TARGET
# Make pkg
ARM64_HASH=$(make_pkg "arm64" "$VERSION" $ARM64_TARGET_DIR)
RET_ARM64=$?
echo "x86_64 hash: $X86_64_HASH"
echo "arm64 hash: $ARM64_HASH"
[ "$RET_ARM64" -eq 0 ] && [ "$RET_X86_64" -eq 0 ]
exit $?

View File

@@ -14,7 +14,7 @@ cargo build --release
# Make zip
$zipName = "termscp-v$version-x86_64-pc-windows-msvc.zip"
Set-Location .\target\release\
Compress-Archive termscp.exe $zipName
Compress-Archive -Force termscp.exe $zipName
# Get checksum
checksum.exe -t sha256 $zipName
Get-FileHash $zipName
Move-Item $zipName .\..\..\dist\pkgs\windows\$zipName

View File

@@ -1,24 +0,0 @@
FROM rust:1.55.0 AS builder
WORKDIR /usr/src/
# Add toolchains
RUN rustup target add x86_64-unknown-linux-gnu
# Install dependencies
RUN apt update && apt install -y \
git \
gcc \
pkg-config \
libssl-dev \
libssh2-1-dev \
libdbus-1-dev \
curl
# Clone repository
RUN git clone https://github.com/veeso/termscp.git
# Set workdir to termscp
WORKDIR /usr/src/termscp/
# Install cargo RPM/Deb
RUN cargo install cargo-strip
# Build for x86_64
RUN cargo build --release --target x86_64-unknown-linux-gnu && cargo strip
CMD ["sh"]

View File

@@ -1,29 +1,26 @@
FROM centos:centos7 as builder
ARG branch
ENV branch=$branch
WORKDIR /usr/src/
# Install dependencies
RUN yum -y install \
git \
gcc \
openssl \
pkgconfig \
gcc \
make \
dbus-devel \
openssl-devel \
bash
libsmbclient-devel \
bash \
rpm-build
# Install rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rust.sh && \
chmod +x /tmp/rust.sh && \
/tmp/rust.sh -y
# Clone repository
RUN git clone --branch $branch https://github.com/veeso/termscp.git
RUN git clone https://github.com/veeso/termscp.git
# Set workdir to termscp
WORKDIR /usr/src/termscp/
# Install cargo arxch
RUN source $HOME/.cargo/env && cargo install cargo-rpm cargo-strip
# Build for x86_64
RUN source $HOME/.cargo/env && cargo build --release && cargo strip
# Build pkgs
RUN source $HOME/.cargo/env && yum -y install rpm-build && cargo rpm init && cargo rpm build
CMD ["sh"]
# Install cargo rpm
RUN source $HOME/.cargo/env && cargo install cargo-rpm
ENTRYPOINT ["tail", "-f", "/dev/null"]

54
dist/build/x86_64_debian12/Dockerfile vendored Normal file
View File

@@ -0,0 +1,54 @@
FROM debian:bookworm
WORKDIR /usr/src/
# Install dependencies
RUN apt update && apt install -y \
git \
gcc \
pkg-config \
libdbus-1-dev \
build-essential \
libsmbclient-dev \
libgit2-dev \
build-essential \
pkg-config \
libbsd-dev \
libcap-dev \
libcups2-dev \
libgnutls28-dev \
libgnutls30 \
libicu-dev \
libjansson-dev \
libkeyutils-dev \
libldap2-dev \
zlib1g-dev \
libpam0g-dev \
libacl1-dev \
libarchive-dev \
libssl-dev \
flex \
bison \
libntirpc-dev \
libglib2.0-dev \
libdbus-1-dev \
libsasl2-dev \
libunistring-dev \
bash \
curl \
cpanminus && \
cpanm Parse::Yapp::Driver;
# Install rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rust.sh && \
chmod +x /tmp/rust.sh && \
/tmp/rust.sh -y && \
. $HOME/.cargo/env && \
cargo version
# Clone repository
RUN git clone https://github.com/veeso/termscp.git
# Set workdir to termscp
WORKDIR /usr/src/termscp/
# Install cargo deb
RUN . $HOME/.cargo/env && cargo install cargo-deb
ENTRYPOINT ["tail", "-f", "/dev/null"]

View File

@@ -1,29 +0,0 @@
FROM debian:jessie
WORKDIR /usr/src/
# Install dependencies
RUN apt update && apt install -y \
git \
gcc \
pkg-config \
libssl-dev \
libssh2-1-dev \
libdbus-1-dev \
curl
# Install rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rust.sh && \
chmod +x /tmp/rust.sh && \
/tmp/rust.sh -y
# Clone repository
RUN git clone https://github.com/veeso/termscp.git
# Set workdir to termscp
WORKDIR /usr/src/termscp/
# Install cargo deb
RUN . $HOME/.cargo/env && cargo install cargo-deb cargo-strip
# Build for x86_64
RUN . $HOME/.cargo/env && cargo build --release && cargo strip
# Build pkgs
RUN . $HOME/.cargo/env && cargo deb
CMD ["sh"]

View File

@@ -1,32 +0,0 @@
FROM debian:stretch
ARG branch
ENV branch=$branch
WORKDIR /usr/src/
# Install dependencies
RUN apt update && apt install -y \
git \
gcc \
pkg-config \
libssl-dev \
libssh2-1-dev \
libdbus-1-dev \
bash \
curl
# Install rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /tmp/rust.sh && \
chmod +x /tmp/rust.sh && \
/tmp/rust.sh -y
# Clone repository
RUN git clone --branch $branch https://github.com/veeso/termscp.git
# Set workdir to termscp
WORKDIR /usr/src/termscp/
# Install cargo deb
RUN . $HOME/.cargo/env && cargo install cargo-deb cargo-strip
# Build for x86_64
RUN . $HOME/.cargo/env && cargo build --release && cargo strip
# Build pkgs
RUN . $HOME/.cargo/env && cargo deb
CMD ["bash"]

View File

@@ -1,26 +1,34 @@
# termscp
<p align="center">
<img src="/assets/images/termscp.svg" width="256" height="256" />
<img src="/assets/images/termscp.svg" alt="logo" width="256" height="256" />
</p>
<p align="center">~ Eine funktionsreiche Terminal-Dateiübertragung ~</p>
<p align="center">
<a href="https://veeso.github.io/termscp/" target="_blank">Webseite</a>
<a href="https://termscp.veeso.dev" target="_blank">Webseite</a>
·
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Installation</a>
<a href="https://termscp.veeso.dev/get-started.html" target="_blank">Installation</a>
·
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">Benutzerhandbuch</a>
<a href="https://termscp.veeso.dev/user-manual.html" target="_blank">Benutzerhandbuch</a>
</p>
<p align="center">
<a href="https://github.com/veeso/termscp"
<a href="https://github.com/veeso/termscp"
><img
height="20"
src="/assets/images/flags/us.png"
src="/assets/images/flags/gb.png"
alt="English"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/pt-BR/README.md"
><img
height="20"
src="/assets/images/flags/br.png"
alt="Brazilian Portuguese"
/></a>
&nbsp;
<a
href="/docs/de/README.md"
><img
@@ -62,8 +70,8 @@
/></a>
</p>
<p align="center">Entwickelt von <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
<p align="center">Aktuelle Version: 0.8.0 (06/01/2022)</p>
<p align="center">Entwickelt von <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Aktuelle Version: 0.19.0 11/11/2025</p>
<p align="center">
<a href="https://opensource.org/licenses/MIT"
@@ -118,18 +126,13 @@
src="https://coveralls.io/repos/github/veeso/termscp/badge.svg"
alt="Coveralls"
/></a>
<a href="https://docs.rs/termscp"
><img
src="https://docs.rs/termscp/badge.svg"
alt="Docs"
/></a>
</p>
---
## Über termscp 🖥
Termscp ist ein funktionsreicher Terminal-Dateitransfer und Explorer mit Unterstützung für SCP/SFTP/FTP/S3. Im Grunde handelt es sich also um ein Terminal-Dienstprogramm mit einer TUI, um eine Verbindung zu einem Remote-Server herzustellen, um Dateien abzurufen und hochzuladen und mit dem lokalen Dateisystem zu interagieren. Es ist **Linux**, **MacOS**, **FreeBSD** und **Windows** kompatibel.
Termscp ist ein funktionsreicher Terminal-Dateitransfer und Explorer mit Unterstützung für SCP/SFTP/FTP/Kube/S3/WebDAV. Im Grunde handelt es sich also um ein Terminal-Dienstprogramm mit einer TUI, um eine Verbindung zu einem Remote-Server herzustellen, um Dateien abzurufen und hochzuladen und mit dem lokalen Dateisystem zu interagieren. Es ist **Linux**, **MacOS**, **FreeBSD** und **Windows** kompatibel.
![Explorer](/assets/images/explorer.gif)
@@ -141,7 +144,10 @@ Termscp ist ein funktionsreicher Terminal-Dateitransfer und Explorer mit Unterst
- **SFTP**
- **SCP**
- **FTP** und **FTPS**
- **Aws S3**
- **Kube**
- **S3**
- **SMB**
- **WebDAV**
- 🖥 Erkunden und bedienen Sie das Dateisystem der Fernbedienung und des lokalen Computers mit einer praktischen Benutzeroberfläche
- Erstellen, Entfernen, Umbenennen, Suchen, Anzeigen und Bearbeiten von Dateien
- ⭐ Verbinden Sie sich über integrierte Lesezeichen und aktuelle Verbindungen mit Ihren Lieblingshosts
@@ -155,6 +161,7 @@ Termscp ist ein funktionsreicher Terminal-Dateitransfer und Explorer mit Unterst
- Anpassbare Dateisortierung
- und viele andere Parameter...
- 📫 Lassen Sie sich benachrichtigen, wenn eine große Datei übertragen wurde
- 🔭 Halten Sie Dateiänderungen mit dem Remote-Host synchron
- 🔐 Speichern Sie Ihr Passwort in Ihrem Betriebssystem-Schlüsseltresor
- 🦀 Rust-powered
- 👀 Entwickelt, um die Leistung im Auge zu behalten
@@ -170,7 +177,7 @@ Wenn Sie zu diesem Projekt beitragen möchten, vergessen Sie nicht, unseren [Bei
Wenn Sie ein Linux-, FreeBSD- oder MacOS-Benutzer sind, installiert dieses einfache Shell-Skript termscp mit einem einzigen Befehl auf Ihrem System:
```sh
curl --proto '=https' --tlsv1.2 -sSLf "https://git.io/JBhDb" | sh
curl -sSLf http://get-termscp.veeso.dev | sh
```
Wenn Sie ein Windows-Benutzer sind, können Sie termscp mit [Chocolatey](https://chocolatey.org/) installieren:
@@ -179,7 +186,7 @@ Wenn Sie ein Windows-Benutzer sind, können Sie termscp mit [Chocolatey](https:/
choco install termscp
```
Für weitere Informationen oder andere Plattformen besuchen Sie bitte [veeso.github.io](https://veeso.github.io/termscp/#get-started), um alle Installationsmethoden anzuzeigen.
Für weitere Informationen oder andere Plattformen besuchen Sie bitte [termscp.veeso.dev](https://termscp.veeso.dev/termscp/get-started.html), um alle Installationsmethoden anzuzeigen.
⚠️ Wenn Sie wissen möchten, wie Sie termscp aktualisieren können, führen Sie einfach termscp über die CLI aus mit: `(sudo) termscp --update` ⚠️
@@ -189,10 +196,12 @@ Für weitere Informationen oder andere Plattformen besuchen Sie bitte [veeso.git
- libssh
- libdbus-1
- pkg-config
- libsmbclient
- **FreeBSD** Benutzer:
- libssh
- dbus
- pkgconf
- libsmbclient
### Optionale Softwareanforderungen ✔️
@@ -223,11 +232,9 @@ Sie können mit einer dieser Plattformen spenden:
---
## User manual and Documentation 📚
## User manual 📚
Das Benutzerhandbuch finden Sie auf der [termscp-Website](https://veeso.github.io/termscp/#user-manual) oder auf [Github](man.md).
Die Entwicklerdokumentation finden Sie in Rust Docs unter <https://docs.rs/termscp>
Das Benutzerhandbuch finden Sie auf der [termscp-Website](https://termscp.veeso.dev/termscp/user-manual.html) oder auf [Github](man.md).
---
@@ -260,7 +267,7 @@ termscp wird von diesen großartigen Projekten unterstützt:
- [self_update](https://github.com/jaemk/self_update)
- [ssh2-rs](https://github.com/alexcrichton/ssh2-rs)
- [suppaftp](https://github.com/veeso/suppaftp)
- [tui-rs](https://github.com/fdehau/tui-rs)
- [ratatui](https://github.com/ratatui-org/ratatui)
- [tui-realm](https://github.com/veeso/tui-realm)
- [whoami](https://github.com/libcala/whoami)
- [wildmatch](https://github.com/becheran/wildmatch)

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +1,34 @@
# termscp
<p align="center">
<img src="/assets/images/termscp.svg" width="256" height="256" />
<img src="/assets/images/termscp.svg" alt="logo" width="256" height="256" />
</p>
<p align="center">~ Una transferencia de archivos de terminal rica en funciones ~</p>
<p align="center">
<a href="https://veeso.github.io/termscp/" target="_blank">Sitio Web</a>
<a href="https://termscp.veeso.dev" target="_blank">Sitio Web</a>
·
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Instalación</a>
<a href="https://termscp.veeso.dev/get-started.html" target="_blank">Instalación</a>
·
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">Manual de usuario</a>
<a href="https://termscp.veeso.dev/user-manual.html" target="_blank">Manual de usuario</a>
</p>
<p align="center">
<a href="https://github.com/veeso/termscp"
><img
height="20"
src="/assets/images/flags/us.png"
src="/assets/images/flags/gb.png"
alt="English"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/pt-BR/README.md"
><img
height="20"
src="/assets/images/flags/br.png"
alt="Brazilian Portuguese"
/></a>
&nbsp;
<a
href="/docs/de/README.md"
><img
@@ -62,8 +70,8 @@
/></a>
</p>
<p align="center">Desarrollado por <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
<p align="center">Versión actual: 0.8.0 (06/01/2022)</p>
<p align="center">Desarrollado por <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Versión actual: 0.19.0 11/11/2025</p>
<p align="center">
<a href="https://opensource.org/licenses/MIT"
@@ -118,18 +126,13 @@
src="https://coveralls.io/repos/github/veeso/termscp/badge.svg"
alt="Coveralls"
/></a>
<a href="https://docs.rs/termscp"
><img
src="https://docs.rs/termscp/badge.svg"
alt="Docs"
/></a>
</p>
---
## Sobre termscp 🖥
Termscp es un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/S3. Básicamente, es una utilidad de terminal con una TUI para conectarse a un servidor remoto para recuperar y cargar archivos e interactuar con el sistema de archivos local. Es compatible con **Linux**, **MacOS**, **FreeBSD** y **Windows**.
Termscp es un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/Kube/S3/WebDAV. Básicamente, es una utilidad de terminal con una TUI para conectarse a un servidor remoto para recuperar y cargar archivos e interactuar con el sistema de archivos local. Es compatible con **Linux**, **MacOS**, **FreeBSD** y **Windows**.
![Explorer](/assets/images/explorer.gif)
@@ -141,7 +144,10 @@ Termscp es un explorador y transferencia de archivos de terminal rico en funcion
- **SFTP**
- **SCP**
- **FTP** y **FTPS**
- **Aws S3**
- **Kube**
- **S3**
- **SMB**
- **WebDAV**
- 🖥 Explore y opere en el sistema de archivos de la máquina local y remota con una interfaz de usuario práctica
- Cree, elimine, cambie el nombre, busque, vea y edite archivos
- ⭐ Conéctese a sus hosts favoritos y conexiones recientes
@@ -155,6 +161,7 @@ Termscp es un explorador y transferencia de archivos de terminal rico en funcion
- Clasificación de archivos personalizable
- y muchos otros parámetros ...
- 📫 Reciba una notificación cuando se haya transferido un archivo grande
- 🔭 Mantenga los cambios de archivos sincronizados con el host remoto
- 🔐 Guarde su contraseña en el almacén de claves de su sistema operativo
- 🦀 Rust-powered
- 👀 Desarrollado sin perder de vista el rendimiento
@@ -170,7 +177,7 @@ Si desea contribuir a este proyecto, no olvide consultar nuestra [guía de contr
Si tu eres un usuario de Linux, FreeBSD o MacOS, este sencillo script de shell instalará termscp en tu sistema con un solo comando:
```sh
curl --proto '=https' --tlsv1.2 -sSLf "https://git.io/JBhDb" | sh
curl -sSLf http://get-termscp.veeso.dev | sh
```
mientras que si eres un usuario de Windows, puedes instalar termscp con [Chocolatey](https://chocolatey.org/):
@@ -179,20 +186,20 @@ mientras que si eres un usuario de Windows, puedes instalar termscp con [Chocola
choco install termscp
```
Para obtener más información u otras plataformas, visite [veeso.github.io](https://veeso.github.io/termscp/#get-started) para ver todos los métodos de instalación.
Para obtener más información u otras plataformas, visite [termscp.veeso.dev](https://termscp.veeso.dev/termscp/get-started.html) para ver todos los métodos de instalación.
⚠️ Si estás buscando cómo actualizar termscp, simplemente ejecute termscp desde CLI con:: `(sudo) termscp --update` ⚠️
### Requisitos ❗
- Usuarios **Linux**:
- libssh
- **Linux** users:
- libdbus-1
- pkg-config
- Usuarios **FreeBSD**:
- libssh
- libsmbclient
- **FreeBSD** or, **NetBSD** users:
- dbus
- pkgconf
- libsmbclient
### Requisitos opcionales ✔️
@@ -225,9 +232,7 @@ Puedes hacer una donación con una de estas plataformas:
## Manual de usuario y documentación 📚
El manual del usuario se puede encontrar en el [sitio web de termscp](https://veeso.github.io/termscp/#user-manual) o en [Github](man.md).
La documentación para desarrolladores se puede encontrar en Rust Docs en <https://docs.rs/termscp>
El manual del usuario se puede encontrar en el [sitio web de termscp](https://termscp.veeso.dev/termscp/user-manual.html) o en [Github](man.md).
---
@@ -260,7 +265,7 @@ termscp funciona con estos increíbles proyectos:
- [self_update](https://github.com/jaemk/self_update)
- [ssh2-rs](https://github.com/alexcrichton/ssh2-rs)
- [suppaftp](https://github.com/veeso/suppaftp)
- [tui-rs](https://github.com/fdehau/tui-rs)
- [ratatui](https://github.com/ratatui-org/ratatui)
- [tui-realm](https://github.com/veeso/tui-realm)
- [whoami](https://github.com/libcala/whoami)
- [wildmatch](https://github.com/becheran/wildmatch)

View File

@@ -4,11 +4,20 @@
- [Uso ❓](#uso-)
- [Argumento dirección 🌎](#argumento-dirección-)
- [Argumento dirección por AWS S3](#argumento-dirección-por-aws-s3)
- [Argumento de dirección Kube](#argumento-de-dirección-kube)
- [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-)
- [Credenciales de AWS S3 🦊](#credenciales-de-aws-s3-)
- [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-)
- [Keybindings ⌨](#keybindings-)
- [Trabaja en varios archivos 🥷](#trabaja-en-varios-archivos-)
- [Trabajar con múltiples archivos 🥷](#trabajar-con-múltiples-archivos-)
- [Ejemplo](#ejemplo)
- [Navegación sincronizada ⏲️](#navegación-sincronizada-)
- [Abierta y abierta con 🚪](#abierta-y-abierta-con-)
- [Marcadores ⭐](#marcadores-)
@@ -27,6 +36,7 @@
- [Text Editor ✏](#text-editor-)
- [Logging 🩺](#logging-)
- [Notificaciones 📫](#notificaciones-)
- [Observador de archivos 🔭](#observador-de-archivos-)
> ❗ Este documento ha sido traducido con Google Translator (y luego lo he revisado a grandes rasgos, pero no puedo hablar el idioma muy bien). Si habla l'idioma, abra un [issue](https://github.com/veeso/termscp/issues/new/choose) utilizando la label COPY o abra un PR 🙏
@@ -34,13 +44,15 @@
termscp se puede iniciar con las siguientes opciones:
`termscp [options]... [protocol://user@address:port:wrkdir] [local-wrkdir]`
`termscp [options]... [protocol://user@address:port:wrkdir] [protocol://user@address:port:wrkdir] [local-wrkdir]`
OR
`termscp [options]... -b [bookmark-name] -b [bookmark-name] [local-wrkdir]`
- `-P, --password <password>` si se proporciona la dirección, la contraseña será este argumento
- `-c, --config` Abrir termscp comenzando desde la página de configuración
- `-b, --address-as-bookmark` resuelve el argumento de la dirección como un nombre de marcador
- `-q, --quiet` Deshabilitar el registro
- `-t, --theme <path>` Importar tema especificado
- `-u, --update` Actualizar termscp a la última versión
- `-v, --version` Imprimir información de la versión
- `-h, --help` Imprimir página de ayuda
@@ -98,6 +110,44 @@ por ejemplo
s3://buckethead@eu-central-1:default:/assets
```
#### Argumento de dirección Kube
En caso de que quieras conectarte a Kube, utiliza la siguiente sintaxis
```txt
kube://[namespace][@<cluster_url>][$</path>]
```
#### Argumento de dirección de WebDAV
En caso de que quieras conectarte a WebDAV utiliza la siguiente sintaxis
```txt
http://<username>:<password>@<url></path>
```
o en caso de que quieras usar https
```txt
https://<username>:<password>@<url></path>
```
#### Argumento dirección por SMB
SMB tiene una sintaxis diferente para el argumento de la dirección CLI, que es diferente si está en Windows u otros sistemas:
**Windows** sintaxis:
```txt
\\[username@]<server-name>\<share>[\path\...]
```
**Other systems** sintaxis:
```txt
smb://[username@]<server-name>[:port]/<share>[/path/.../]
```
#### Cómo se puede proporcionar la contraseña 🔐
Probablemente haya notado que, al proporcionar la dirección como argumento, no hay forma de proporcionar la contraseña.
@@ -107,9 +157,45 @@ 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 <archivo-tema>`
#### 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.
---
## Credenciales de AWS S3 🦊
## S3 parámetros de conexión
Estos parámetros son necesarios para conectarse a aws s3 y otros servidores compatibles con s3:
- AWS S3:
- **bucket name**
- **region**
- *profile* (si no se proporciona: "default")
- *access key* (A menos que sea pública)
- *secret access key* (A menos que sea pública)
- *security token* (si es requerido)
- *session token* (si es requerido)
- new path style: **NO**
- Otros puntos finales de S3:
- **bucket name**
- **endpoint**
- *access key* (A menos que sea pública)
- *secret access key* (A menos que sea pública)
- new path style: **YES**
### Credenciales de S3 🦊
Para conectarse a un bucket de Aws S3, obviamente debe proporcionar algunas credenciales.
Básicamente, hay tres formas de lograr esto.
@@ -165,40 +251,64 @@ Para cambiar de panel, debe escribir `<LEFT>` para mover el panel del explorador
| `<BACKTAB>` | Cambiar entre la pestaña de registro y el explorador | |
| `<A>` | Alternar archivos ocultos | All |
| `<B>` | Ordenar archivos por | Bubblesort? |
| `<C|F5>` | Copiar archivo / directorio | Copy |
| `<D|F7>` | Hacer directorio | Directory |
| `<E|F8|DEL>` | Eliminar archivo | Erase |
| `<C\|F5>` | Copiar archivo / directorio | Copy |
| `<D\|F7>` | Hacer directorio | Directory |
| `<E\|F8\|DEL>` | Eliminar archivo | Erase |
| `<F>` | Búsqueda de archivos | Find |
| `<G>` | Ir a la ruta proporcionada | Go to |
| `<H|F1>` | Mostrar ayuda | Help |
| `<H\|F1>` | Mostrar ayuda | Help |
| `<I>` | Mostrar información sobre el archivo | Info |
| `<K>` | Crear un enlace simbólico que apunte a la entrada seleccionada actualmente | symlinK |
| `<L>` | Recargar contenido del directorio / Borrar selección | List |
| `<M>` | Seleccione un archivo | Mark |
| `<N>` | Crear un nuevo archivo con el nombre proporcionado | New |
| `<O|F4>` | Editar archivo | Open |
| `<Q|F10>` | Salir de termscp | Quit |
| `<R|F6>` | Renombrar archivo | Rename |
| `<S|F2>` | Guardar archivo como... | Save |
| `<O\|F4>` | Editar archivo | Open |
| `<P>` | Open log panel | Panel |
| `<Q\|F10>` | Salir de termscp | Quit |
| `<R\|F6>` | Renombrar archivo | Rename |
| `<S\|F2>` | Guardar archivo como... | Save |
| `<T>` | Sincronizar los cambios en la ruta seleccionada con el control remoto | Track |
| `<U>` | Ir al directorio principal | Upper |
| `<V|F3>` | Abrir archivo con el programa predeterminado | View |
| `<V\|F3>` | Abrir archivo con el programa predeterminado | View |
| `<W>` | Abrir archivo con el programa proporcionado | With |
| `<X>` | Ejecutar un comando | eXecute |
| `<Y>` | Alternar navegación sincronizada | sYnc |
| `<Z>` | Cambiar ppermisos de archivo | |
| `</>` | Filtrar archivos (se admite tanto regex como coincidencias con comodines) | |
| `<CTRL+A>` | Seleccionar todos los archivos | |
| `<ALT+A>` | Deseleccionar todos los archivos | |
| `<CTRL+C>` | Abortar el proceso de transferencia de archivos | |
| `<CTRL+S>` | Obtener el tamaño total de la ruta seleccionada | Size |
| `<CTRL+T>` | Mostrar todas las rutas sincronizadas | Track |
### Trabaja en varios archivos 🥷
### Trabajar con múltiples archivos 🥷
Puede optar por trabajar en varios archivos, seleccionándolos presionando `<M>`, para seleccionar el archivo actual, o presionando `<CTRL + A>`, que seleccionará todos los archivos en el directorio de trabajo.
Una vez que un archivo está marcado para su selección, se mostrará con un `*` a la izquierda.
Al trabajar en la selección, solo se procesará el archivo seleccionado para las acciones, mientras que el elemento resaltado actual se ignorará.
También es posible trabajar en varios archivos desde el panel de resultados de búsqueda.
Todas las acciones están disponibles cuando se trabaja con varios archivos, pero tenga en cuenta que algunas acciones funcionan de forma ligeramente diferente. Vamos a sumergirnos en:
Puedes optar por trabajar con varios archivos, usando estos controles:
- *Copy*: cada vez que copie un archivo, se le pedirá que inserte el nombre de destino. Cuando se trabaja con varios archivos, este nombre se refiere al directorio de destino donde se copiarán todos estos archivos.
- *Rename*: igual que copiar, pero moverá archivos allí.
- *Save as*: igual que copiar, pero los escribirá allí.
- `<M>`: marcar un archivo para selección
- `<CTRL+A>`: seleccionar todos los archivos del directorio actual
- `<ALT+A>`: deseleccionar todos los archivos
Una vez marcado, el archivo será **mostrado con un fondo resaltado** .
Cuando se trabaja con una selección, solo los archivos seleccionados serán procesados; el archivo resaltado actual será ignorado.
También se puede trabajar con múltiples archivos desde el panel de resultados de búsqueda.
Todas las acciones están disponibles con archivos múltiples, pero algunas funcionan de forma algo distinta. Veamos:
- *Copiar*: al copiar, se pedirá el nombre de destino. Para varios archivos, es el directorio donde se copiarán.
- *Renombrar*: igual que copiar, pero mueve los archivos.
- *Guardar como*: igual que copiar, pero escribe los archivos allí.
Si seleccionas un archivo en un directorio (ej. `/home`) y cambias de directorio, seguirá seleccionado y se mostrará en la **cola de transferencia** en el panel inferior.
Cuando se selecciona un archivo, se asocia la carpeta *remota* actual con él; si se transfiere, será a esa carpeta.
#### Ejemplo
Si seleccionamos `/home/a.txt` localmente y estamos en `/tmp` en remoto, luego cambiamos a `/var`, seleccionamos `/var/b.txt` y estamos en `/home` en el panel remoto, el resultado de transferir será:
- `/home/a.txt` transferido a `/tmp/a.txt`
- `/var/b.txt` transferido a `/home/b.txt`
### Navegación sincronizada ⏲️
@@ -309,7 +419,7 @@ Estos parámetros se pueden cambiar:
- **Local File formatter syntax**: sintaxis para mostrar información de archivo para cada archivo en el explorador local. Consulte [Formato del explorador de archivos](#formato-del-explorador-de-archivos).
- **Enable notifications?**: Si se establece en "Sí", se mostrarán las notificaciones.
- **Notifications: minimum transfer size**: si el tamaño de la transferencia es mayor o igual que el valor especificado, se mostrarán notificaciones de transferencia. Los valores aceptados están en formato `{UNSIGNED} B/KB/MB/GB/TB/PB`
- **SSH configuration path**: Configure el archivo de configuración SSH para usar al conectarse a un servidor SCP / SFTP. Si no se configura (está vacío), no se utilizará ningún archivo. Puede especificar una ruta que comience con `~` para indicar la ruta de inicio (por ejemplo, `~/.ssh/config`)
- **SSH configuration path**: Configure el archivo de configuración SSH para usar al conectarse a un servidor SCP / SFTP. Si no se configura (está vacío), no se utilizará ningún archivo. Puede especificar una ruta que comience con `~` para indicar la ruta de inicio (por ejemplo, `~/.ssh/config`). Se especifican los parámetros soportados [AQUI](https://github.com/veeso/ssh2-config#exposed-attributes).
### SSH Key Storage 🔐
@@ -451,9 +561,9 @@ En caso de que el archivo esté ubicado en un host remoto, el archivo se descarg
termscp escribe un archivo de registro para cada sesión, que se escribe en
- `$HOME/.config/termscp/termscp.log` en Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` en MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` en Windows
- `$HOME/.cache/termscp/termscp.log` en Linux/BSD
- `$HOME/Library/Caches/termscp/termscp.log` en MacOs
- `FOLDERID_LocalAppData\termscp\termscp.log` en Windows
el registro no se rotará, sino que se truncará después de cada lanzamiento de termscp, por lo que si desea informar un problema y desea adjuntar su archivo de registro, recuerde guardar el archivo de registro en un lugar seguro antes de usar termscp de nuevo.
El registro por defecto informa en el nivel *INFO*, por lo que no es muy detallado.
@@ -485,3 +595,26 @@ Termscp enviará notificaciones de escritorio para este tipo de eventos:
❗ Si prefiere mantener las notificaciones desactivadas, puede simplemente ingresar a la configuración y configurar `Enable notifications?` En `No` 😉.
❗ Si desea cambiar el tamaño mínimo de transferencia para mostrar notificaciones, puede cambiar el valor en la configuración con la tecla `Notifications: minimum transfer size` y configurarlo como mejor le convenga 🙂.
## Observador de archivos 🔭
El observador de archivos le permite configurar una lista de rutas para sincronizar con los hosts remotos.
Esto significa que siempre que se detecte un cambio en el sistema de archivos local en la ruta sincronizada, el cambio se informará automáticamente a la ruta del host remoto configurado, dentro de los 5 segundos.
Puede establecer tantas rutas para sincronizar como prefiera:
1. Coloque el cursor en el explorador local en el directorio/archivo que desea mantener sincronizado
2. Vaya al directorio en el que desea que se informen los cambios en el host remoto
3. Presione `<T>`
4. Responda `<YES>` a la ventana emergente de radio
Para dejar de mirar, simplemente presione `<T>` en la ruta sincronizada local (o en cualquiera de sus subcarpetas)
O simplemente puede presionar `<CTRL + T>` y presionar `<ENTER>` en la ruta sincronizada que desea dejar de ver.
Estos cambios se informarán al host remoto:
- Nuevos archivos, cambios de archivos
- Archivo movido / renombrado
- Archivo eliminado/desvinculado
> ❗ El vigilante trabaja solo en una dirección (local > remota). NO es posible sincronizar automáticamente los cambios de remoto a local.

View File

@@ -1,26 +1,34 @@
# termscp
<p align="center">
<img src="/assets/images/termscp.svg" width="256" height="256" />
<img src="/assets/images/termscp.svg" alt="logo" width="256" height="256" />
</p>
<p align="center">~ Un file transfer de terminal riche en fonctionnalités ~</p>
<p align="center">
<a href="https://veeso.github.io/termscp/" target="_blank">Site internet</a>
<a href="https://termscp.veeso.dev" target="_blank">Site internet</a>
·
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Installation</a>
<a href="https://termscp.veeso.dev/get-started.html" target="_blank">Installation</a>
·
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">Manuel de l'Utilisateur</a>
<a href="https://termscp.veeso.dev/user-manual.html" target="_blank">Manuel de l'Utilisateur</a>
</p>
<p align="center">
<a href="https://github.com/veeso/termscp"
><img
height="20"
src="/assets/images/flags/us.png"
src="/assets/images/flags/gb.png"
alt="English"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/pt-BR/README.md"
><img
height="20"
src="/assets/images/flags/br.png"
alt="Brazilian Portuguese"
/></a>
&nbsp;
<a
href="/docs/de/README.md"
><img
@@ -62,8 +70,8 @@
/></a>
</p>
<p align="center">Développé par <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
<p align="center">Version actuelle: 0.8.0 (06/01/2022)</p>
<p align="center">Développé par <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Version actuelle: 0.19.0 11/11/2025</p>
<p align="center">
<a href="https://opensource.org/licenses/MIT"
@@ -118,18 +126,13 @@
src="https://coveralls.io/repos/github/veeso/termscp/badge.svg"
alt="Coveralls"
/></a>
<a href="https://docs.rs/termscp"
><img
src="https://docs.rs/termscp/badge.svg"
alt="Docs"
/></a>
</p>
---
## À propos des termscp 🖥
Termscp est un file transfer et explorateur de fichiers de terminal riche en fonctionnalités, avec support pour SCP/SFTP/FTP/S3. Essentiellement c'est une utilitaire terminal avec une TUI pour se connecter à un serveur distant pour télécharger de fichiers et interagir avec le système de fichiers local. Il est compatible avec **Linux**, **MacOS**, **FreeBSD** et **Windows**.
Termscp est un file transfer et explorateur de fichiers de terminal riche en fonctionnalités, avec support pour SCP/SFTP/FTP/Kube/S3/WebDAV. Essentiellement c'est une utilitaire terminal avec une TUI pour se connecter à un serveur distant pour télécharger de fichiers et interagir avec le système de fichiers local. Il est compatible avec **Linux**, **MacOS**, **FreeBSD** et **Windows**.
![Explorer](/assets/images/explorer.gif)
@@ -141,7 +144,10 @@ Termscp est un file transfer et explorateur de fichiers de terminal riche en fon
- **SFTP**
- **SCP**
- **FTP** et **FTPS**
- **Aws S3**
- **Kube**
- **S3**
- **SMB**
- **WebDAV**
- 🖥 Explorer et opérer sur le système de fichiers distant et local avec une interface utilisateur pratique.
- Créer, supprimer, renommer, rechercher, afficher et modifier des fichiers
- ⭐ Connectez-vous à vos hôtes préférés via des signets et des connexions récentes.
@@ -155,6 +161,7 @@ Termscp est un file transfer et explorateur de fichiers de terminal riche en fon
- tri de fichiers personallisable
- et bien d'autres paramètres...
- 📫 Recevez une notification quande un gros fichier est télécharger.
- 🔭 Gardez les modifications de fichiers synchronisées avec l'hôte distant
- 🔐 Enregistre tes mots de passe dans le key vault du systeme.
- 🦀 Rust-powered
- 👀 Développé en gardant un œil sur les performances
@@ -170,7 +177,7 @@ Si tu veux contribuer à ce projet, n'oublié pas de consulter notre [guide de c
Si tu es un utilisateur Linux, FreeBSD ou MacOS ce simple shell script installera termscp sur te système en un seule commande:
```sh
curl --proto '=https' --tlsv1.2 -sSLf "https://git.io/JBhDb" | sh
curl -sSLf http://get-termscp.veeso.dev | sh
```
tandis que si tu es un utilisateur Windows, tu peux installer termscp avec [Chocolatey](https://chocolatey.org/):
@@ -179,20 +186,20 @@ tandis que si tu es un utilisateur Windows, tu peux installer termscp avec [Choc
choco install termscp
```
Pour plus d'informations sur les autres méthodes d'installation, veuillez visiter [veeso.github.io](https://veeso.github.io/termscp/#get-started).
Pour plus d'informations sur les autres méthodes d'installation, veuillez visiter [termscp.veeso.dev](https://termscp.veeso.dev/termscp/get-started.html).
⚠️ Si tu cherche comme de mettre à jour termscp, tu dois exécuter cette commande dans le terminal: `(sudo) termscp --update` ⚠️
### Requis ❗
- utilisateurs **Linux**:
- libssh
- **Linux** users:
- libdbus-1
- pkg-config
- utilisateurs **FreeBSD**:
- libssh
- libsmbclient
- **FreeBSD** or, **NetBSD** users:
- dbus
- pkgconf
- libsmbclient
### Requis facultatives ✔️
@@ -225,7 +232,7 @@ Tu peux faire un don avec l'une de ces plateformes:
## Manuel d'utilisateur et Documentation 📚
Le manuel d'utilisateur peut être trouvé sur le [site de termscp](https://veeso.github.io/termscp/#user-manual) ou sur [Github](man.md).
Le manuel d'utilisateur peut être trouvé sur le [site de termscp](https://termscp.veeso.dev/termscp/user-manual.html) ou sur [Github](man.md).
La documentation peut être trouvé sur Rust Docs <https://docs.rs/termscp>
@@ -260,7 +267,7 @@ termscp est soutenu par ces projets impressionnants:
- [self_update](https://github.com/jaemk/self_update)
- [ssh2-rs](https://github.com/alexcrichton/ssh2-rs)
- [suppaftp](https://github.com/veeso/suppaftp)
- [tui-rs](https://github.com/fdehau/tui-rs)
- [ratatui](https://github.com/ratatui-org/ratatui)
- [tui-realm](https://github.com/veeso/tui-realm)
- [whoami](https://github.com/libcala/whoami)
- [wildmatch](https://github.com/becheran/wildmatch)

View File

@@ -4,11 +4,20 @@
- [Usage ❓](#usage-)
- [Argument d'adresse 🌎](#argument-dadresse-)
- [Argument d'adresse AWS S3](#argument-dadresse-aws-s3)
- [Argument d'adresse Kube](#argument-dadresse-kube)
- [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-)
- [Identifiants AWS S3 🦊](#identifiants-aws-s3-)
- [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-)
- [Raccourcis clavier ⌨](#raccourcis-clavier-)
- [Travailler sur plusieurs fichiers 🥷](#travailler-sur-plusieurs-fichiers-)
- [Exemple](#exemple)
- [Navigation synchronisée ⏲️](#navigation-synchronisée-)
- [Ouvrir et ouvrir avec 🚪](#ouvrir-et-ouvrir-avec-)
- [Signets ⭐](#signets-)
@@ -27,18 +36,21 @@
- [Éditeur de texte ✏](#éditeur-de-texte-)
- [Fichier Journal 🩺](#fichier-journal-)
- [Notifications 📫](#notifications-)
- [Observateur de fichiers 🔭](#observateur-de-fichiers-)
## Usage ❓
termscp peut être démarré avec les options suivantes :
`termscp [options]... [protocol://user@address:port:wrkdir] [local-wrkdir]`
`termscp [options]... [protocol://user@address:port:wrkdir] [protocol://user@address:port:wrkdir] [local-wrkdir]`
ou
`termscp [options]... -b [bookmark-name] -b [bookmark-name] [local-wrkdir]`
- `-P, --password <password>` si l'adresse est fournie, le mot de passe sera cet argument
- `-c, --config` Ouvrir termscp à partir de la page de configuration
- `-b, --address-as-bookmark` résoudre l'argument d'adresse en tant que nom de signet
- `-q, --quiet` Désactiver la journalisation
- `-t, --theme <path>` Importer le thème spécifié
- `-u, --update` Mettre à jour termscp vers la dernière version
- `-v, --version` Imprimer les informations sur la version
- `-h, --help` Imprimer la page d'aide
@@ -96,6 +108,44 @@ e.g.
s3://buckethead@eu-central-1:default:/assets
```
#### Argument d'adresse Kube
Si vous souhaitez vous connecter à Kube, utilisez la syntaxe suivante
```txt
kube://[namespace][@<cluster_url>][$</path>]
```
#### Argument d'adresse WebDAV
Dans le cas où vous souhaitez vous connecter à WebDAV, utilisez la syntaxe suivante
```txt
http://<username>:<password>@<url></path>
```
ou dans le cas où vous souhaitez utiliser https
```txt
https://<username>:<password>@<url></path>
```
#### Argument d'adresse SMB
SMB a une syntaxe différente pour l'argument d'adresse CLI, qui est différente que vous soyez sur Windows ou sur d'autres systèmes :
syntaxe **Windows**:
```txt
\\[username@]<server-name>\<share>[\path\...]
```
syntaxe **Other systems**:
```txt
smb://[username@]<server-name>[:port]/<share>[/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.
@@ -105,9 +155,45 @@ 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 <fichier-thème>`
#### 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.
---
## Identifiants AWS S3 🦊
## S3 paramètres de connexion
Ces paramètres sont requis pour se connecter à aws s3 et à d'autres serveurs compatibles s3 :
- AWS S3:
- **bucket name**
- **region**
- *profile* (si non fourni : "par défaut")
- *access key* (sauf si public)
- *secret access key* (sauf si public)
- *security token* (si nécessaire)
- *session token* (si nécessaire)
- new path style: **NO**
- Autres points de terminaison S3:
- **bucket name**
- **endpoint**
- *access key* (sauf si public)
- *secret access key* (sauf si public)
- new path style: **YES**
### Identifiants S3 🦊
Afin de vous connecter à un compartiment Aws S3, vous devez évidemment fournir des informations d'identification.
Il existe essentiellement trois manières d'y parvenir.
@@ -163,40 +249,64 @@ Pour changer de panneau, vous devez taper `<LEFT>` pour déplacer le panneau de
| `<BACKTAB>` | Basculer entre l'onglet journal et l'explorateur | |
| `<A>` | Basculer les fichiers cachés | All |
| `<B>` | Trier les fichiers par | Bubblesort? |
| `<C|F5>` | Copier le fichier/répertoire | Copy |
| `<D|F7>` | Créer un dossier | Directory |
| `<E|F8|DEL>` | Supprimer le fichier (Identique à `DEL`) | Erase |
| `<C\|F5>` | Copier le fichier/répertoire | Copy |
| `<D\|F7>` | Créer un dossier | Directory |
| `<E\|F8\|DEL>` | Supprimer le fichier (Identique à `DEL`) | Erase |
| `<F>` | Rechercher des fichiers | Find |
| `<G>` | Aller au chemin fourni | Go to |
| `<H|F1>` | Afficher l'aide | Help |
| `<H\|F1>` | Afficher l'aide | Help |
| `<I>` | Afficher les informations sur le fichier ou le dossier sélectionné | Info |
| `<K>` | Créer un lien symbolique pointant vers l'entrée actuellement sélectionnée | symlinK |
| `<L>` | Recharger le contenu du répertoire actuel / Effacer la sélection | List |
| `<M>` | Sélectionner un fichier | Mark |
| `<N>` | Créer un nouveau fichier avec le nom fourni | New |
| `<O|F4>` | Modifier le fichier | Open |
| `<Q|F10>` | Quitter termscp | Quit |
| `<R|F6>` | Renommer le fichier | Rename |
| `<S|F2>` | Enregistrer le fichier sous... | Save |
| `<O\|F4>` | Modifier le fichier | Open |
| `<P>` | Ouvre le panel de journals | Panel |
| `<Q\|F10>` | Quitter termscp | Quit |
| `<R\|F6>` | Renommer le fichier | Rename |
| `<S\|F2>` | Enregistrer le fichier sous... | Save |
| `<T>` | Synchroniser les modifications apportées au chemin sélectionné | Track |
| `<U>` | Aller dans le répertoire parent | Upper |
| `<V|F3>` | Ouvrir le fichier avec le programme défaut pour le type de fichier | View |
| `<V\|F3>` | Ouvrir le fichier avec le programme défaut pour le type de fichier | View |
| `<W>` | Ouvrir le fichier avec le programme spécifié | With |
| `<X>` | Exécuter une commande | eXecute |
| `<Y>` | Basculer la navigation synchronisée | sYnc |
| `<Z>` | Changer permissions de fichier | |
| `</>` | Filtrer les fichiers (les expressions régulières et les correspondances génériques sont prises en charge) | |
| `<CTRL+A>` | Sélectionner tous les fichiers | |
| `<ALT+A>` | Desélectionner tous les fichiers | |
| `<CTRL+C>` | Abandonner le processus de transfert de fichiers | |
| `<CTRL+S>` | Obtenir la taille totale du chemin sélectionné | Size |
| `<CTRL+T>` | Afficher tous les chemins synchronisés | Track |
### Travailler sur plusieurs fichiers 🥷
Vous pouvez choisir de travailler sur plusieurs fichiers, en les sélectionnant en appuyant sur `<M>`, afin de sélectionner le fichier actuel, ou en appuyant sur `<CTRL+A>`, ce qui sélectionnera tous les fichiers dans le répertoire de travail.
Une fois qu'un fichier est marqué pour la sélection, il sera affiché avec un `*` sur la gauche.
Lorsque vous travaillez sur la sélection, seul le fichier sélectionné sera traité pour les actions, tandis que l'élément en surbrillance actuel sera ignoré.
Il est également possible de travailler sur plusieurs fichiers dans le panneau des résultats de recherche.
Toutes les actions sont disponibles lorsque vous travaillez avec plusieurs fichiers, mais sachez que certaines actions fonctionnent de manière légèrement différente. Plongeons dans:
Vous pouvez choisir de travailler sur plusieurs fichiers avec ces simples commandes :
- *Copy*: chaque fois que vous copiez un fichier, vous serez invité à insérer le nom de destination. Lorsque vous travaillez avec plusieurs fichiers, ce nom fait référence au répertoire de destination où tous ces fichiers seront copiés.
- *Rename*: identique à la copie, mais y déplacera les fichiers.
- *Save as*: identique à la copie, mais les y écrira.
- `<M>` : marquer un fichier à sélectionner
- `<CTRL+A>` : sélectionner tous les fichiers du répertoire actuel
- `<ALT+A>` : désélectionner tous les fichiers
Une fois sélectionné, un fichier sera **affiché avec un fond en surbrillance** .
Lorsquon travaille avec des sélections, seules les fichiers sélectionnés seront affectés par les actions, tandis que l'élément actuellement surligné sera ignoré.
Il est également possible de travailler avec plusieurs fichiers depuis le panneau des résultats de recherche.
Toutes les actions sont disponibles avec des fichiers multiples, mais certaines peuvent se comporter différemment. Détails :
- *Copier* : lors de la copie, il vous sera demandé un nom de destination. Avec plusieurs fichiers, cela correspond au dossier de destination.
- *Renommer* : identique à la copie, mais déplace les fichiers.
- *Enregistrer sous* : identique à la copie, mais enregistre les fichiers à cet emplacement.
Si vous sélectionnez un fichier dans un dossier (ex. `/home`) puis changez de répertoire, il restera sélectionné et sera affiché dans la **file dattente de transfert** en bas.
Lorsquun fichier est sélectionné, le dossier *distant* courant lui est associé ; en cas de transfert, il sera envoyé vers ce dossier.
#### Exemple
Si on sélectionne `/home/a.txt` localement et que le panneau distant est sur `/tmp`, puis on passe à `/var`, on sélectionne `/var/b.txt` et que le panneau distant est sur `/home`, le transfert donnera :
- `/home/a.txt` transféré vers `/tmp/a.txt`
- `/var/b.txt` transféré vers `/home/b.txt`
### Navigation synchronisée ⏲️
@@ -307,7 +417,7 @@ Ces paramètres peuvent être modifiés :
- **Local File formatter syntax**: syntaxe pour afficher les informations de fichier pour chaque fichier dans l'explorateur local. Voir [File explorer format](#format-de-lexplorateur-de-fichiers)
- **Enable notifications?**: S'il est défini sur `Yes`, les notifications seront affichées.
- **Notifications: minimum transfer size**: si la taille du transfert est supérieure ou égale à la valeur spécifiée, les notifications de transfert seront affichées. Les valeurs acceptées sont au format `{UNSIGNED} B/KB/MB/GB/TB/PB`
- **SSH configuration path** : définissez le fichier de configuration SSH à utiliser lors de la connexion à un serveur SCP/SFTP. S'il n'est pas défini (vide), aucun fichier ne sera utilisé. Vous pouvez spécifier un chemin commençant par `~` pour indiquer le chemin d'accueil (par exemple `~/.ssh/config`)
- **SSH configuration path** : définissez le fichier de configuration SSH à utiliser lors de la connexion à un serveur SCP/SFTP. S'il n'est pas défini (vide), aucun fichier ne sera utilisé. Vous pouvez spécifier un chemin commençant par `~` pour indiquer le chemin d'accueil (par exemple `~/.ssh/config`). Les paramétrages disponibles pour la configuration sont listées [ICI](https://github.com/veeso/ssh2-config#exposed-attributes).
### SSH Key Storage 🔐
@@ -449,9 +559,9 @@ Si le fichier se trouve sur l'hôte distant, le fichier sera d'abord télécharg
termscp écrit un fichier journal pour chaque session, qui est écrit à
- `$HOME/.config/termscp/termscp.log` sous Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` sous MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` sous Windows
- `$HOME/.cache/termscp/termscp.log` sous Linux/BSD
- `$HOME/Library/Caches/termscp/termscp.log` sous MacOs
- `FOLDERID_LocalAppData\termscp\termscp.log` sous Windows
le journal ne sera pas tourné, mais sera simplement tronqué après chaque lancement de termscp, donc si vous souhaitez signaler un problème et que vous souhaitez joindre votre fichier journal, n'oubliez pas de sauvegarder le fichier journal dans un endroit sûr avant de l'utiliser termescp à nouveau.
@@ -484,3 +594,26 @@ Termscp enverra des notifications de bureau pour ce type d'événements :
❗ Si vous préférez désactiver les notifications, vous pouvez simplement accéder à la configuration et définir `Enable notifications?` sur `No` 😉.
❗ Si vous souhaitez modifier la taille de transfert minimale pour afficher les notifications, vous pouvez modifier la valeur dans la configuration avec la touche `Notifications: minimum transfer size` et la définir sur ce qui vous convient le mieux 🙂.
## Observateur de fichiers 🔭
L'observateur de fichiers vous permet de configurer une liste de chemins à synchroniser avec les hôtes distants.
Cela signifie que chaque fois qu'un changement sur le système de fichiers local sera détecté sur le chemin synchronisé, le changement sera automatiquement signalé au chemin de l'hôte distant configuré, dans les 5 secondes.
Vous pouvez définir autant de chemins à synchroniser que vous préférez :
1. Placez le curseur de l'explorateur local sur le répertoire/fichier que vous souhaitez conserver synchronisé
2. Accédez au répertoire dans lequel vous souhaitez que les modifications soient signalées sur l'hôte distant
3. Appuyez sur `<T>`
4. Répondez `<YES>` à la fenêtre contextuelle de la radio
Pour annuler la surveillance, appuyez simplement sur `<T>` sur le chemin synchronisé local (ou sur l'un de ses sous-dossiers)
OU vous pouvez simplement appuyer sur `<CTRL + T>` et appuyer sur `<ENTER>` jusqu'au chemin synchronisé que vous souhaitez désactiver.
Ces modifications seront signalées à l'hôte distant :
- Nouveaux fichiers, modifications de fichiers
- Fichier déplacé / renommé
- Fichier supprimé / dissocié
> ❗ Le watcher ne fonctionne que dans un sens (local > distant). Il n'est PAS possible de synchroniser automatiquement les changements de distant à local.

View File

@@ -1,26 +1,34 @@
# termscp
<p align="center">
<img src="/assets/images/termscp.svg" width="256" height="256" />
<img src="/assets/images/termscp.svg" alt="logo" width="256" height="256" />
</p>
<p align="center">~ Un file transfer ricco di funzionalità ~</p>
<p align="center">
<a href="https://veeso.github.io/termscp/" target="_blank">Sito</a>
<a href="https://termscp.veeso.dev" target="_blank">Sito</a>
·
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">Installazione</a>
<a href="https://termscp.veeso.dev/get-started.html" target="_blank">Installazione</a>
·
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">Manuale utente</a>
<a href="https://termscp.veeso.dev/user-manual.html" target="_blank">Manuale utente</a>
</p>
<p align="center">
<a href="https://github.com/veeso/termscp"
><img
height="20"
src="/assets/images/flags/us.png"
src="/assets/images/flags/gb.png"
alt="English"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/pt-BR/README.md"
><img
height="20"
src="/assets/images/flags/br.png"
alt="Brazilian Portuguese"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/de/README.md"
><img
@@ -62,8 +70,8 @@
/></a>
</p>
<p align="center">Sviluppato da <a href="https://veeso.github.io/" target="_blank">@veeso</a></p>
<p align="center">Versione corrente: 0.8.0 (06/01/2022)</p>
<p align="center">Sviluppato da <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Versione corrente: 0.19.0 11/11/2025</p>
<p align="center">
<a href="https://opensource.org/licenses/MIT"
@@ -118,18 +126,13 @@
src="https://coveralls.io/repos/github/veeso/termscp/badge.svg"
alt="Coveralls"
/></a>
<a href="https://docs.rs/termscp"
><img
src="https://docs.rs/termscp/badge.svg"
alt="Docs"
/></a>
</p>
---
## Riguardo a termscp 🖥
Termscp è un file transfer ed explorer ricco di funzionalità, con supporto a SCP/SFTP/FTP/S3. In pratica è un utility su terminale con una terminal user-interface per connettersi a server remoti per scambiare file ed interagire con il file system sia locale che remoto. È compatibile con **Linux**, **MacOS**, **FreeBSD** e **Windows**.
Termscp è un file transfer ed explorer ricco di funzionalità, con supporto a SCP/SFTP/FTP/Kube/S3/WebDAV. In pratica è un utility su terminale con una terminal user-interface per connettersi a server remoti per scambiare file ed interagire con il file system sia locale che remoto. È compatibile con **Linux**, **MacOS**, **FreeBSD** e **Windows**.
![Explorer](/assets/images/explorer.gif)
@@ -141,7 +144,10 @@ Termscp è un file transfer ed explorer ricco di funzionalità, con supporto a S
- **SFTP**
- **SCP**
- **FTP** and **FTPS**
- **Aws S3**
- **Kube**
- **S3**
- **SMB**
- **WebDAV**
- 🖥 Esplora e opera sia sul file system locale che su quello remoto con una UI di facile utilizzo.
- Crea, rimuove, rinomina, cerca, visualizza e modifica file
- ⭐ Connettiti ai tuoi host preferiti tramite la funzionalità integrata dei segnalibri e delle connessioni recenti.
@@ -155,6 +161,7 @@ Termscp è un file transfer ed explorer ricco di funzionalità, con supporto a S
- Imposta l'ordinamento di file e cartelle
- e tanto altro...
- 📫 Ricevi notifiche desktop quando un file di cospicue dimensioni è stato trasferito
- 🔭 Mantieni sincronizzate le modifiche con l'host remoto
- 🔐 Salva le password degli host remoti nel keyring predefinito dal tuo sistema operativo
- 🦀 Rust-powered
- 👀 Progettato tenendo conto delle performance
@@ -170,7 +177,7 @@ Se vuoi contribuire al progetto, non dimenticarti di leggere la [contribute guid
Se sei un utente che utilizza Linux, FreeBSD o MacOS, questo shell script installerà termscp sul tuo sistema con un comando secco:
```sh
curl --proto '=https' --tlsv1.2 -sSLf "https://git.io/JBhDb" | sh
curl -sSLf http://get-termscp.veeso.dev | sh
```
mentre se sei un utente Windows, puoi installare termscp con [Chocolatey](https://chocolatey.org/):
@@ -179,20 +186,20 @@ mentre se sei un utente Windows, puoi installare termscp con [Chocolatey](https:
choco install termscp
```
Per ulteriori informazioni sui metodi di installazione su altre piattaforme, visita [veeso.github.io](https://veeso.github.io/termscp/#get-started).
Per ulteriori informazioni sui metodi di installazione su altre piattaforme, visita [termscp.veeso.dev](https://termscp.veeso.dev/termscp/get-started.html).
⚠️ Se stavi cercando come aggiornare la tua versione di termscp, puoi semplicemente lanciare termscp con questi argomenti: `(sudo) termscp --update` ⚠️
### Requisiti ❗
- Utenti **Linux**:
- libssh
- **Linux** users:
- libdbus-1
- pkg-config
- Utenti **FreeBSD**:
- libssh
- libsmbclient
- **FreeBSD** or, **NetBSD** users:
- dbus
- pkgconf
- libsmbclient
### Requisiti opzionali ✔️
@@ -223,11 +230,9 @@ Puoi fare una donazione tramite una di queste piattaforme:
---
## Manuale e documentazione 📚
## Manuale utente 📚
Il manuale utente lo puoi trovare sul [sito di termscp](https://veeso.github.io/termscp/#user-manual) o su [Github](man.md).
La documentazione per sviluppatori la puoi trovare su Rust Docs <https://docs.rs/termscp>.
Il manuale utente lo puoi trovare sul [sito di termscp](https://termscp.veeso.dev/termscp/user-manual.html) o su [Github](man.md).
---
@@ -260,7 +265,7 @@ se termscp esiste, è anche grazie a questi fantastici progetti:
- [self_update](https://github.com/jaemk/self_update)
- [ssh2-rs](https://github.com/alexcrichton/ssh2-rs)
- [suppaftp](https://github.com/veeso/suppaftp)
- [tui-rs](https://github.com/fdehau/tui-rs)
- [ratatui](https://github.com/ratatui-org/ratatui)
- [tui-realm](https://github.com/veeso/tui-realm)
- [whoami](https://github.com/libcala/whoami)
- [wildmatch](https://github.com/becheran/wildmatch)

View File

@@ -4,11 +4,20 @@
- [Argomenti da linea di comando ❓](#argomenti-da-linea-di-comando-)
- [Argomento indirizzo 🌎](#argomento-indirizzo-)
- [Argomento indirizzo per AWS S3](#argomento-indirizzo-per-aws-s3)
- [Argomento indirizzo Kube](#argomento-indirizzo-kube)
- [Argomento indirizzo per WebDAV](#argomento-indirizzo-per-webdav)
- [Indirizzo SMB](#indirizzo-smb)
- [Come fornire la password 🔐](#come-fornire-la-password-)
- [Credenziali Aws S3 🦊](#credenziali-aws-s3-)
- [Sottocomandi](#sottocomandi)
- [Importare un tema](#importare-un-tema)
- [Installare lultima 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-)
- [Abbinamento tasti ⌨](#abbinamento-tasti-)
- [Lavora su più file 🥷](#lavora-su-più-file-)
- [Lavora con più file 🥷](#lavora-con-più-file-)
- [Esempio](#esempio)
- [Synchronized browsing ⏲️](#synchronized-browsing-)
- [Apri e apri con 🚪](#apri-e-apri-con-)
- [Segnalibri ⭐](#segnalibri-)
@@ -27,18 +36,21 @@
- [Editor di testo ✏](#editor-di-testo-)
- [Logging 🩺](#logging-)
- [Notifiche 📫](#notifiche-)
- [File watcher 🔭](#file-watcher-)
## Argomenti da linea di comando ❓
termscp può essere lanciato con questi argomenti:
`termscp [options]... [protocol://user@address:port:wrkdir] [local-wrkdir]`
`termscp [options]... [protocol://user@address:port:wrkdir] [protocol://user@address:port:wrkdir] [local-wrkdir]`
O
`termscp [options]... -b [bookmark-name] -b [bookmark-name] [local-wrkdir]`
- `-P, --password <password>` Se viene fornito l'argomento indirizzo, questa sarà la password utilizzata per autenticarsi
- `-c, --config` Apri la configurazione di termscp
- `-b, --address-as-bookmark` risolve l'argomento indirizzo come nome di un segnalibro
- `-q, --quiet` Disabilita i log
- `-t, --theme <path>` Importa il tema al percorso fornito
- `-u, --update` Aggiorna termscp all'ultima versione
- `-v, --version` Mostra a video le informazioni sulla versione attualmente installata
- `-h, --help` Mostra la pagina di aiuto.
@@ -94,6 +106,44 @@ e.g.
s3://buckethead@eu-central-1:default:/assets
```
#### Argomento indirizzo Kube
Nel caso tu voglia connetterti a Kube usa la seguente sintassi
```txt
kube://[namespace][@<cluster_url>][$</path>]
```
#### Argomento indirizzo per WebDAV
Nel caso in cui si desideri connettersi a WebDAV utilizzare la seguente sintassi
```txt
http://<username>:<password>@<url></path>
```
oppure nel caso in cui si desideri utilizzare https
```txt
https://<username>:<password>@<url></path>
```
#### Indirizzo SMB
SMB ha una sintassi differente rispetto agli altri protocolli e cambia in base al sistema operativo:
**Windows**:
```txt
\\[username@]<server-name>\<share>[\path\...]
```
**Altri sistemi**:
```txt
smb://[username@]<server-name>[:port]/<share>[/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:
@@ -102,9 +152,45 @@ 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 <file-tema>`
#### Installare lultima 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.
---
## Credenziali Aws S3 🦊
## Parametri di connessione S3
Questi parametri sono necessari per connettersi ad un bucket Aws s3 o ad uno storage compatibile:
- AWS S3:
- **bucket name**
- **region**
- *profile* (se non fornito: "default")
- *access key* (a meno che non sia pubblico)
- *secret access key* (a meno che non sia pubblico)
- *security token* (se necessario)
- *session token* (se necessario)
- new path style: **NO**
- Other S3 endpoints:
- **bucket name**
- **endpoint**
- *access key* (a meno che non sia pubblico)
- *secret access key* (a meno che non sia pubblico)
- new path style: **YES**
### Credenziali S3 🦊
Per connettersi ad un bucket S3 devi come già saprai fornire le credenziali fornite da AWS.
Ci sono tre modi per passare queste credenziali a termscp.
@@ -159,40 +245,64 @@ Per cambiare pannello ti puoi muovere con le frecce, `<LEFT>` per andare sul pan
| `<BACKTAB>` | Cambia tra explorer e pannello di log | |
| `<A>` | Mostra/nascondi file nascosti | All |
| `<B>` | Ordina file per | Bubblesort? |
| `<C|F5>` | Copia file/directory | Copy |
| `<D|F7>` | Crea directory | Directory |
| `<E|F8|DEL>` | Elimina file | Erase |
| `<C\|F5>` | Copia file/directory | Copy |
| `<D\|F7>` | Crea directory | Directory |
| `<E\|F8\|DEL>` | Elimina file | Erase |
| `<F>` | Cerca file (wild match supportato) | Find |
| `<G>` | Vai al percorso indicato | Go to |
| `<H|F1>` | Mostra help | Help |
| `<H\|F1>` | Mostra help | Help |
| `<I>` | Mostra informazioni per il file selezionato | Info |
| `<K>` | Crea un link simbolico che punta al file selezionato | symlinK |
| `<L>` | Ricarica posizione corrente / pulisci selezione file | List |
| `<M>` | Seleziona file | Mark |
| `<N>` | Crea nuovo file con il nome fornito | New |
| `<O|F4>` | Modifica file; Vedi text editor | Open |
| `<Q|F10>` | Termina termscp | Quit |
| `<R|F6>` | Rinomina file | Rename |
| `<S|F2>` | Salva file con nome | Save |
| `<O\|F4>` | Modifica file; Vedi text editor | Open |
| `<P>` | Apri pannello log | Panel |
| `<Q\|F10>` | Termina termscp | Quit |
| `<R\|F6>` | Rinomina file | Rename |
| `<S\|F2>` | Salva file con nome | Save |
| `<T>` | Sincronizza il percorso locale con l'host remoto | Track |
| `<U>` | Vai alla directory padre | Upper |
| `<V|F3>` | Apri il file con il programma definito dal sistema | View |
| `<V\|F3>` | Apri il file con il programma definito dal sistema | View |
| `<W>` | Apri il file con il programma specificato | With |
| `<X>` | Esegui comando shell | eXecute |
| `<Y>` | Abilita/disabilita Sync-Browsing | sYnc |
| `<Z>` | Modifica permessi file | |
| `</>` | Filtra i file (supporta sia regex che wildmatch ) | |
| `<CTRL+A>` | Seleziona tutti i file | |
| `<ALT+A>` | Deseleziona tutti i file | |
| `<CTRL+C>` | Annulla trasferimento file | |
| `<CTRL+S>` | Ottieni la dimensione totale del percorso selezionato | Size |
| `<CTRL+T>` | Visualizza tutti i percorsi sincronizzati | Track |
### Lavora su più file 🥷
### Lavora con più file 🥷
Puoi lavorare su una selezione di file, marcandoli come selezionati tramite `<M>`, per selezionare il file corrente o con `<CTRL+A` per selezionarli tutti.
Una volta che un file è marcato, sarà visualizzato con un `*` prima del nome.
Quando lavori con una selezioni, solo i file selezionati saranno presi in considerazione (l'eventuale file evidenziato sarà ignorato).
È possibile operare su più file anche nel pannello di ricerca.
Tutte le azioni sono disponibili quando si lavora sulle selezioni, ma occhio, che alcune azioni si comporteranno in maniera leggermente differente. Vediamo quali e come:
Puoi scegliere di lavorare con più file, usando questi semplici comandi:
- *Copia*: Se copi un file, ti verrà richiesto di inserire il nome delle destinazione, ma quando lavori con la selezione, il nome si riferisce alla directory di destinazione, mentre il nome del file rimarrà inviariato.
- *Rinomina*: Come il copia, ma li sposterà.
- *Salva con nome*: Come il copia, ma li trasferirà.
- `<M>`: marca un file per la selezione
- `<CTRL+A>`: seleziona tutti i file nella directory corrente
- `<ALT+A>`: deseleziona tutti i file
Una volta che un file è stato selezionato, verrà **evidenziato con uno sfondo colorato** .
Quando lavori su una selezione, solo i file selezionati verranno processati per le azioni, mentre l'elemento attualmente evidenziato sarà ignorato.
È possibile lavorare con più file anche dal pannello dei risultati di ricerca.
Tutte le azioni sono disponibili anche quando si lavora con più file, ma alcune funzionano in modo leggermente diverso. Ecco i dettagli:
- *Copia*: quando copi un file, ti verrà chiesto di inserire il nome di destinazione. Con più file selezionati, questo nome rappresenta la cartella di destinazione dove verranno copiati.
- *Rinomina*: come la copia, ma i file verranno spostati lì.
- *Salva come*: come la copia, ma i file verranno salvati lì.
Se selezioni un file in una directory (es. `/home`) e poi cambi directory, il file rimarrà selezionato e sarà visibile nella **coda di trasferimento** nel pannello inferiore.
Quando un file viene selezionato, la directory *remota* corrente viene associata allelemento; quindi, se il file viene trasferito, verrà trasferito nella directory associata.
#### Esempio
Se selezioniamo un file locale `/home/a.txt`, siamo su `/tmp` nel pannello remoto, poi ci spostiamo su `/var`, selezioniamo `/var/b.txt`, e sul pannello remoto siamo su `/home`, eseguendo il trasferimento otterremo:
- `/home/a.txt` trasferito su `/tmp/a.txt`
- `/var/b.txt` trasferito su `/home/b.txt`
### Synchronized browsing ⏲️
@@ -305,7 +415,7 @@ Questi parametri possono essere impostati:
- **Local File formatter syntax**: La formattazione da usare per formattare i file sull'explorer locale. Vedi [File explorer format](#file-explorer-format)
- **Enable notifications?**: Se impostato a `yes`, le notifiche desktop saranno abilitate.
- **Notifications: minimum transfer size**: se la dimensione di un trasferimento supera o è uguale al valore impostato, al termine del trasferimento riceverai una notifica desktop (se queste sono abilitate). Il formato del valore dev'essere `{UNSIGNED} B/KB/MB/GB/TB/PB`
- **SSH configuration path**: Imposta il percorso del file di configurazione per SSH, per quando ci si connette ad un server SFTP/SCP. Se lasciato vuoto, nessun file verrà usato. Il percorso può anche iniziare con `~` per indicare il percorso della home dell'utente attuale (e.s. `~/.ssh/config`).
- **SSH configuration path**: Imposta il percorso del file di configurazione per SSH, per quando ci si connette ad un server SFTP/SCP. Se lasciato vuoto, nessun file verrà usato. Il percorso può anche iniziare con `~` per indicare il percorso della home dell'utente attuale (e.s. `~/.ssh/config`). I parametri supportati dalla configurazioni sono descritti [QUI](https://github.com/veeso/ssh2-config#exposed-attributes).
### SSH Key Storage 🔐
@@ -448,9 +558,9 @@ Nel caso il file si trovi su host remoto, il file verrà prima scaricato tempora
termscp scrive un file di log per ogni sessione, nel percorso seguente:
- `$HOME/.config/termscp/termscp.log` su Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` su MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` su Windows
- `$HOME/.cache/termscp/termscp.log` su Linux/BSD
- `$HOME/Library/Caches/termscp/termscp.log` su MacOs
- `FOLDERID_LocalAppData\termscp\termscp.log` su Windows
Il log non viene ruotato, ma viene troncato ad ogni lancio di termscp, quindi se devi riportare un issue, non avviare termscp fino a che non avrai salvato il file di log.
I log sono di default riportati a livello *INFO*, quindi non sono particolarmente parlanti.
@@ -482,3 +592,26 @@ termscp invierà notifiche destkop per i seguenti eventi:
❗ Se vuoi disabilitare le notifiche, è sufficiente andare in configurazione ed impostare `Enable notifications?` a `No` 😉.
❗ Se vuoi modificare la soglia minima per le notifiche dei trasferimenti, puoi impostare il valore di `Notifications: minimum transfer size` in configurazione 🙂.
## File watcher 🔭
Il file watcher ti permette di impostare una lista di percorsi da sincronizzare con l'host remoto.
Ciò implica che ogni volta che una modifica verrà rilevata al percorso sincronizzato, la modifica verrà automaticamente sincronizzata con l'host remoto, entro 5 secondi.
Puoi impostare quanti percorsi preferisci da sincronizzare:
1. Porta il cursore dell'explorer sulla cartella/file che vuoi sincronizzare
2. Vai alla directory sull'explorer remoto dove vuoi riportare le modifiche
3. Premi `<T>`
4. Rispondi `<YES>` alla domanda se vuoi sincronizzare il percorso
Per terminare la sincronizzazione, premi `<T>`, al percorso locale sincronizzato (od in qualsiasi sua sottocartella)
OPPURE, puoi semplicemente premere `<CTRL+T>` e premi `<ENTER>` sul percorso che vuoi desincronizzare.
Queste modifiche verranno applicate sull'host remoto:
- Nuovi file, modifiche
- File spostati o rinominati
- File rimossi
> ❗ Il watcher funziona solo in maniera unidirezionale locale > remoto. NON è possibile tracciare le modifiche da remoto a locale.

View File

@@ -4,11 +4,20 @@
- [Usage ❓](#usage-)
- [Address argument 🌎](#address-argument-)
- [AWS S3 address argument](#aws-s3-address-argument)
- [Kube address argument](#kube-address-argument)
- [WebDAV address argument](#webdav-address-argument)
- [SMB address argument](#smb-address-argument)
- [How Password can be provided 🔐](#how-password-can-be-provided-)
- [Aws S3 credentials 🦊](#aws-s3-credentials-)
- [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-)
- [Keybindings ⌨](#keybindings-)
- [Work on multiple files 🥷](#work-on-multiple-files-)
- [Example](#example)
- [Synchronized browsing ⏲️](#synchronized-browsing-)
- [Open and Open With 🚪](#open-and-open-with-)
- [Bookmarks ⭐](#bookmarks-)
@@ -27,26 +36,31 @@
- [Text Editor ✏](#text-editor-)
- [Logging 🩺](#logging-)
- [Notifications 📫](#notifications-)
- [File watcher 🔭](#file-watcher-)
## Usage ❓
termscp can be started with the following options:
`termscp [options]... [protocol://user@address:port:wrkdir] [local-wrkdir]`
`termscp [options]... [protocol://user@address:port:wrkdir] [protocol://user@address:port:wrkdir] [local-wrkdir]`
- `-P, --password <password>` if address is provided, password will be this argument
- `-c, --config` Open termscp starting from the configuration page
OR
`termscp [options]... -b [bookmark-name] -b [bookmark-name] [local-wrkdir]`
AND any combination of the two
- `-P, --password <password>` if address is provided, password will be this argument. A password *can* be specified for each remote provided. The order must be the same of the address argument. The use of this parameter is discouraged.
- `-b, --address-as-bookmark` resolve address argument as a bookmark name
- `-q, --quiet` Disable logging
- `-t, --theme <path>` Import specified theme
- `-u, --update` Update termscp to latest version
- `-v, --version` Print version info
- `-h, --help` Print help page
termscp can be started in two different mode, if no extra arguments is provided, termscp will show the authentication form, where the user will be able to provide the parameters required to connect to the remote peer.
termscp can be started in three different modes, if no extra arguments is provided, termscp will show the authentication form, where the user will be able to provide the parameters required to connect to the remote peer.
Alternatively, the user can provide an address as argument to skip the authentication form and starting directly the connection to the remote server.
If address argument is provided you can also provide the start working directory for local host
If address argument or bookmark name is provided you can also provide the start working directory for local host
### Address argument 🌎
@@ -96,6 +110,44 @@ e.g.
s3://buckethead@eu-central-1:default:/assets
```
#### Kube address argument
In case you want to connect to Kube use the following syntax
```txt
kube://[namespace][@<cluster_url>][$</path>]
```
#### WebDAV address argument
In case you want to connect to webDAV use the following syntax
```txt
http://<username>:<password>@<url></path>
```
or in case you want to use https
```txt
https://<username>:<password>@<url></path>
```
#### SMB address argument
SMB has a different syntax for CLI address argument, which is different whether you're on Windows or other systems:
**Windows** syntax:
```txt
\\[username@]<server-name>\<share>[\path\...]
```
**Other systems** syntax:
```txt
smb://[username@]<server-name>[:port]/<share>[/path/.../]
```
#### How Password can be provided 🔐
You have probably noticed, that, when providing the address as argument, there's no way to provide the password.
@@ -105,9 +157,45 @@ Password can be basically provided through 3 ways when address argument is provi
- Via `sshpass`: you can provide password via `sshpass`, e.g. `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31`
- You will be prompted for it: if you don't use any of the previous methods, you will be prompted for the password, as happens with the more classics tools such as `scp`, `ssh`, etc.
### Subcommands
#### Import a theme
Run termscp as `termscp theme <theme-file>`
#### Install latest version
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.
---
## Aws S3 credentials 🦊
## S3 connection parameters
These parameters are required to connect to aws s3 and other s3 compatible servers:
- AWS S3:
- **bucket name**
- **region**
- *profile* (if not provided: "default")
- *access key* (unless if public)
- *secret access key* (unless if public)
- *security token* (if required)
- *session token* (if required)
- new path style: **NO**
- Other S3 endpoints:
- **bucket name**
- **endpoint**
- *access key* (unless if public)
- *secret access key* (unless if public)
- new path style: **YES**
### S3 credentials 🦊
In order to connect to an Aws S3 bucket you must obviously provide some credentials.
There are basically three ways to achieve this:
@@ -163,41 +251,66 @@ In order to change panel you need to type `<LEFT>` to move the remote explorer p
| `<BACKTAB>` | Switch between log tab and explorer | |
| `<A>` | Toggle hidden files | All |
| `<B>` | Sort files by | Bubblesort? |
| `<C|F5>` | Copy file/directory | Copy |
| `<D|F7>` | Make directory | Directory |
| `<E|F8|DEL>` | Delete file | Erase |
| `<C\|F5>` | Copy file/directory | Copy |
| `<D\|F7>` | Make directory | Directory |
| `<E\|F8\|DEL>`| Delete file | Erase |
| `<F>` | Search for files (wild match is supported) | Find |
| `<G>` | Go to supplied path | Go to |
| `<H|F1>` | Show help | Help |
| `<H\|F1>` | Show help | Help |
| `<I>` | Show info about selected file or directory | Info |
| `<K>` | Create symlink pointing to the currently selected entry | symlinK |
| `<L>` | Reload current directory's content / Clear selection | List |
| `<M>` | Select a file | Mark |
| `<N>` | Create new file with provided name | New |
| `<O|F4>` | Edit file; see Text editor | Open |
| `<Q|F10>` | Quit termscp | Quit |
| `<R|F6>` | Rename file | Rename |
| `<S|F2>` | Save file as... | Save |
| `<O\|F4>` | Edit file; see Text editor | Open |
| `<P>` | Open log panel | Panel |
| `<Q\|F10>` | Quit termscp | Quit |
| `<R\|F6>` | Rename file | Rename |
| `<S\|F2>` | Save file as... | Save |
| `<T>` | Synchronize changes to selected path to remote | Track |
| `<U>` | Go to parent directory | Up |
| `<V|F3>` | Open file with default program for filetype | View |
| `<V\|F3>` | Open file with default program for filetype | View |
| `<W>` | Open file with provided program | With |
| `<X>` | Execute a command | eXecute |
| `<Y>` | Toggle synchronized browsing | sYnc |
| `<Z>` | Change file mode | |
| `</>` | Filter files (both regex and wildmatch is supported) | |
| `<CTRL+A>` | Select all files | |
| `<ALT+A>` | Deselect all files | |
| `<CTRL+C>` | Abort file transfer process | |
| `<CTRL+S>` | Get total size of the selected path | Size |
| `<CTRL+T>` | Show all synchronized paths | Track |
### Work on multiple files 🥷
You can opt to work on multiple files, selecting them pressing `<M>`, in order to select the current file, or pressing `<CTRL+A>`, which will select all the files in the working directory.
Once a file is marked for selection, it will be displayed with a `*` on the left.
You can opt to work on multiple files, with these simple controls:
- `<M>`: mark a file for selection
- `<CTRL+A>`: select all files in the current directory
- `<ALT+A>`: deselect all files
Once a file is marked for selection, it will be **displayed with an highlighted background**.
When working on selection, only selected file will be processed for actions, while the current highlighted item will be ignored.
It is possible to work on multiple files also when in the find result panel.
All the actions are available when working with multiple files, but be aware that some actions work in a slightly different way. Let's dive in:
- *Copy*: whenever you copy a file, you'll be prompted to insert the destination name. When working with multiple file, this name refers to the destination directory where all these files will be copied.
- *Rename*: same as copy, but will move files there.
- *Save as*: same as copy, but will write them there.
If you select a file in a directory (e.g. `/home`) and then you change directory the file will be kept selected and it will be displayed in the **transfer queue** in the bottom panel.
When a file gets selected the current *remote* directory is associated to its entry; so in case the file gets transferred it will be transferred to the directory associated to the file.
#### Example
If we select a file on local `/home/a.txt` and we're currently at `/tmp` on remote and then we move to `/var` and we select `/var/b.txt` and on the remote panel we're at `/home` and we perform a transfer the result will be:
- `/home/a.txt` transferred to `/tmp/a.txt`
- `/var/b.txt` transferred to `/home/b.txt`
### Synchronized browsing ⏲️
When enabled, synchronized browsing, will allow you to synchronize the navigation between the two panels.
@@ -308,7 +421,7 @@ These parameters can be changed:
- **Local File formatter syntax**: syntax to display file info for each file in the local explorer. See [File explorer format](#file-explorer-format)
- **Enable notifications?**: If set to `Yes`, notifications will be displayed.
- **Notifications: minimum transfer size**: if transfer size is greater or equal than the specified value, notifications for transfer will be displayed. The accepted values are in format `{UNSIGNED} B/KB/MB/GB/TB/PB`
- **SSH configuration path**: Set SSH configuration file to use when connecting to a SCP/SFTP server. If unset (empty) no file will be used. You can specify a path starting with `~` to indicate the home path (e.g. `~/.ssh/config`)
- **SSH configuration path**: Set SSH configuration file to use when connecting to a SCP/SFTP server. If unset (empty) no file will be used. You can specify a path starting with `~` to indicate the home path (e.g. `~/.ssh/config`). The parameters supported by termscp are specified [HERE](https://github.com/veeso/ssh2-config#exposed-attributes).
### SSH Key Storage 🔐
@@ -450,9 +563,9 @@ In case the file is located on remote host, the file will be first downloaded in
termscp writes a log file for each session, which is written at
- `$HOME/.config/termscp/termscp.log` on Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` on MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` on Windows
- `$HOME/.cache/termscp/termscp.log` on Linux/BSD
- `$HOME/Library/Caches/termscp/termscp.log` on MacOs
- `FOLDERID_LocalAppData\termscp\termscp.log` on Windows
the log won't be rotated, but will just be truncated after each launch of termscp, so if you want to report an issue and you want to attach your log file, keep in mind to save the log file in a safe place before using termscp again.
The logging by default reports in *INFO* level, so it is not very verbose.
@@ -484,3 +597,28 @@ Termscp will send Desktop notifications for these kind of events:
❗ If you prefer to keep notifications turned off, you can just enter setup and set `Enable notifications?` to `No` 😉.
❗ If you want to change the minimum transfer size to display notifications, you can change the value in the configuration with key `Notifications: minimum transfer size` and set it to whatever suits better for you 🙂.
---
## File watcher 🔭
The file watcher allows you to setup a list of paths to synchronize with the remote hosts.
This means that whenever a change on the local file system will be detected on the synchronized path, the change will be automatically reported to the configured remote host path, within 5 seconds.
You can set as many paths to synchronize as you prefer:
1. Put the cursor on the local explorer on the directory/file you want to keep synchronized
2. Go to the directory you want the changes to be reported to on the remote host
3. Press `<T>`
4. Answer `<YES>` to the radio popup
To unwatch, just press `<T>` on the local synchronized path (or to any of its subfolders)
OR you can just press `<CTRL+T>` and press `<ENTER>` to the synchronized path you want to unwatch.
These changes will be reported to the remote host:
- New files, file changes
- File moved/renamed
- File removed/unlinked
> ❗ The watcher works only in one direction (local > remote). It is NOT possible to synchronize automatically the changes from remote to local.

View File

@@ -1,4 +1,4 @@
Termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/S3.
Termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/Kube/S3/WebDAV.
Basically is a terminal utility with an TUI to connect to a remote server to retrieve and upload files and
to interact with the local file system.
@@ -8,7 +8,7 @@ Features:
- SFTP
- SCP
- FTP and FTPS
- Aws S3
- S3
- 🖥 Explore and operate on the remote and on the local machine file system with a handy UI
- Create, remove, rename, search, view and edit files
- ⭐ Connect to your favourite hosts through built-in bookmarks and recent connections

317
docs/pt-BR/README.md Normal file
View File

@@ -0,0 +1,317 @@
# termscp
<p align="center">
<img src="/assets/images/termscp.svg" alt="termscp logo" width="256" height="256" />
</p>
<p align="center">~ Uma transferência de arquivos de terminal rica em recursos ~</p>
<p align="center">
<a href="https://termscp.veeso.dev" target="_blank">Website</a>
·
<a href="https://termscp.veeso.dev/get-started.html" target="_blank">Instalação</a>
·
<a href="https://termscp.veeso.dev/user-manual.html" target="_blank">Manual do usuário</a>
</p>
<p align="center">
<a href="https://github.com/veeso/termscp"
><img
height="20"
src="/assets/images/flags/gb.png"
alt="English"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/pt-BR/README.md"
><img
height="20"
src="/assets/images/flags/br.png"
alt="Brazilian Portuguese"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/de/README.md"
><img
height="20"
src="/assets/images/flags/de.png"
alt="Deutsch"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/es/README.md"
><img
height="20"
src="/assets/images/flags/es.png"
alt="Español"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/fr/README.md"
><img
height="20"
src="/assets/images/flags/fr.png"
alt="Français"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/it/README.md"
><img
height="20"
src="/assets/images/flags/it.png"
alt="Italiano"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/zh-CN/README.md"
><img
height="20"
src="/assets/images/flags/cn.png"
alt="简体中文"
/></a>
</p>
<p align="center">Desenvolvido por <a href="https://veeso.me/" target="_blank">@veeso</a></p>
<p align="center">Versão atual: 0.19.0 11/11/2025</p>
<p align="center">
<a href="https://opensource.org/licenses/MIT"
><img
src="https://img.shields.io/badge/License-MIT-teal.svg"
alt="License-MIT"
/></a>
<a href="https://github.com/veeso/termscp/stargazers"
><img
src="https://img.shields.io/github/stars/veeso/termscp?style=flat"
alt="Repo stars"
/></a>
<a href="https://crates.io/crates/termscp"
><img
src="https://img.shields.io/crates/d/termscp.svg"
alt="Downloads counter"
/></a>
<a href="https://crates.io/crates/termscp"
><img
src="https://img.shields.io/crates/v/termscp.svg"
alt="Latest version"
/></a>
<a href="https://ko-fi.com/veeso">
<img
src="https://img.shields.io/badge/donate-ko--fi-red"
alt="Ko-fi"
/></a>
</p>
<p align="center">
<a href="https://github.com/veeso/termscp/actions"
><img
src="https://github.com/veeso/termscp/workflows/Linux/badge.svg"
alt="Linux CI"
/></a>
<a href="https://github.com/veeso/termscp/actions"
><img
src="https://github.com/veeso/termscp/workflows/MacOS/badge.svg"
alt="MacOS CI"
/></a>
<a href="https://github.com/veeso/termscp/actions"
><img
src="https://github.com/veeso/termscp/workflows/Windows/badge.svg"
alt="Windows CI"
/></a>
<a href="https://coveralls.io/github/veeso/termscp"
><img
src="https://coveralls.io/repos/github/veeso/termscp/badge.svg"
alt="Coveralls"
/></a>
</p>
---
## Sobre o termscp 🖥
Termscp é um explorador e utilitário de transferência de arquivos com uma interface de terminal, com suporte para SCP/SFTP/FTP/Kube/S3/WebDAV. Basicamente, é uma ferramenta de terminal com uma interface de usuário para conectar-se a um servidor remoto para baixar e enviar arquivos e interagir com o sistema de arquivos local. Ele é compatível com **Linux**, **MacOS**, **FreeBSD**, **NetBSD** e **Windows**.
![Explorer](/assets/images/explorer.gif)
---
## Recursos 🎁
- 📁 Diferentes protocolos de comunicação
- **SFTP**
- **SCP**
- **FTP** e **FTPS**
- **Kube**
- **S3**
- **SMB**
- **WebDAV**
- 🖥 Explore e opere no sistema de arquivos remoto e local com uma interface amigável
- Crie, remova, renomeie, pesquise, visualize e edite arquivos
- ⭐ Conecte-se aos seus hosts favoritos por meio de marcadores integrados e conexões recentes
- 📝 Veja e edite arquivos com suas aplicações favoritas
- 💁 Autenticação SFTP/SCP com chaves SSH e nome de usuário/senha
- 🐧 Compatível com Windows, Linux, FreeBSD, NetBSD e MacOS
- 🎨 Personalize do seu jeito!
- Temas
- Formato de explorador de arquivos customizável
- Editor de texto personalizável
- Ordenação de arquivos customizável
- e muitos outros parâmetros...
- 📫 Receba notificações no Desktop quando um arquivo grande for transferido
- 🔭 Mantenha as alterações de arquivos sincronizadas com o host remoto
- 🔐 Salve sua senha no cofre de senhas do sistema operacional
- 🦀 Feito em Rust
- 👀 Desenvolvido com foco em desempenho
- 🦄 Atualizações frequentes e incríveis
---
## Como começar 🚀
Se você está pensando em instalar o termscp, eu quero te agradecer 💜 ! Espero que você goste do termscp!
Se você quiser contribuir para este projeto, não se esqueça de verificar nosso [guia de contribuição](CONTRIBUTING.md).
Se você é um usuário de Linux, FreeBSD ou MacOS, este simples script de shell instalará o termscp no seu sistema com um único comando:
```sh
curl --proto '=https' --tlsv1.2 -sSLf "https://git.io/JBhDb" | sh
```
> ❗ A instalação no MacOS requer [Homebrew](https://brew.sh/), caso contrário, o compilador Rust será instalado.
Se você é um usuário de Windows, pode instalar o termscp com [Chocolatey](https://chocolatey.org/):
```ps
choco install termscp
```
Usuários do NetBSD podem instalar o termscp pelos repositórios oficiais.
```sh
pkgin install termscp
```
Usuários do Arch Linux podem instalar o termscp pelos repositórios oficiais.
```sh
pacman -S termscp
```
Para mais informações ou outras plataformas, visite [termscp.veeso.dev](https://termscp.veeso.dev/get-started.html) para ver todos os métodos de instalação.
⚠️ Se você quer saber como atualizar o termscp, basta executar o termscp a partir do CLI com: `(sudo) termscp --update` ⚠️
### Requisitos ❗
- Para usuários de **Linux**:
- libdbus-1
- pkg-config
- libsmbclient
- Para usuários de **FreeBSD** ou **NetBSD**:
- dbus
- pkgconf
- libsmbclient
### Requisitos Opcionais ✔️
Estes requisitos não são obrigatórios para rodar o termscp, mas para aproveitar todos os seus recursos.
- Para usuários de **Linux/FreeBSD**:
- Para **abrir** arquivos via `V` (pelo menos um dos seguintes)
- *xdg-open*
- *gio*
- *gnome-open*
- *kde-open*
- Para usuários de **Linux**:
- Um gerenciador de chaves: leia mais no [Manual do Usuário](docs/man.md#linux-keyring)
- Para usuários do **WSL**
- Para **abrir** arquivos via `V` (pelo menos um dos seguintes)
- [wslu](https://github.com/wslutilities/wslu)
---
## Apoie o desenvolvedor ☕
Se você gosta do termscp e está grato pelo trabalho que fiz, considere uma pequena doação 🥳
Você pode fazer uma doação por meio de uma dessas plataformas:
[![ko-fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/veeso)
[![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)](https://www.paypal.me/chrisintin)
---
## Manual do Usuário 📚
O manual do usuário pode ser encontrado no [site do termscp](https://termscp.veeso.dev/user-manual.html) ou no [Github](docs/man.md).
---
## Próximos Recursos 🧪
Para **2023**, haverá duas grandes atualizações durante o ano.
Além de novos recursos, o desenvolvimento do termscp agora está focado em melhorias de UX e desempenho, então, se você tiver alguma sugestão, sinta-se à vontade para abrir um problema.
---
## Contribuições e problemas 🤝🏻
Contribuições, relatos de bugs, novos recursos e perguntas são bem-vindos! 😉
Se você tiver alguma pergunta ou preocupação, ou se quiser sugerir um novo recurso, ou apenas melhorar o termscp, sinta-se à vontade para abrir um problema ou um PR.
Uma contribuição **apreciada** seria a tradução do manual do usuário e do README para **outros idiomas**.
Por favor, siga [nosso guia de contribuição](CONTRIBUTING.md).
---
## Mudanças ⏳
Veja o changelog do termscp [AQUI](CHANGELOG.md).
---
## Impulsionado por 💪
O termscp é impulsionado por esses projetos incríveis:
- [bytesize](https://github.com/hyunsik/bytesize)
- [crossterm](https://github.com/crossterm-rs/crossterm)
- [edit](https://github.com/milkey-mouse/edit)
- [keyring-rs](https://github.com/hwchen/keyring-rs)
- [open-rs](https://github.com/Byron/open-rs)
- [pavao](https://github.com/veeso/pavao)
- [remotefs](https://github.com/veeso/remotefs-rs)
- [rpassword](https://github.com/conradkleinespel/rpassword)
- [self_update](https://github.com/jaemk/self_update)
- [ratatui](https://github.com/ratatui-org/ratatui)
- [tui-realm](https://github.com/veeso/tui-realm)
- [whoami](https://github.com/libcala/whoami)
- [wildmatch](https://github.com/becheran/wildmatch)
---
## Galeria 🎬
> Termscp Home
![Auth](/assets/images/auth.gif)
> Marcadores
![Bookmarks](/assets/images/bookmarks.gif)
> Configuração
![Setup](/assets/images/config.gif)
> Editor de Texto
![TextEditor](/assets/images/text-editor.gif)
---
## Licença 📃
O termscp é licenciado sob a licença MIT.
Você pode ler a licença completa [AQUI](LICENSE).

621
docs/pt-BR/man.md Normal file
View File

@@ -0,0 +1,621 @@
# Manual do Usuário 🎓
- [Manual do Usuário 🎓](#manual-do-usuário-)
- [Uso ❓](#uso-)
- [Argumento de Endereço 🌎](#argumento-de-endereço-)
- [Argumento de Endereço do AWS S3](#argumento-de-endereço-do-aws-s3)
- [Argumento de endereço Kube](#argumento-de-endereço-kube)
- [Argumento de Endereço do WebDAV](#argumento-de-endereço-do-webdav)
- [Argumento de Endereço do SMB](#argumento-de-endereço-do-smb)
- [Como a Senha Pode Ser Fornecida 🔐](#como-a-senha-pode-ser-fornecida-)
- [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-)
- [Atalhos de Teclado ⌨](#atalhos-de-teclado-)
- [Trabalhar com múltiplos arquivos 🥷](#trabalhar-com-múltiplos-arquivos-)
- [Exemplo](#exemplo)
- [Navegação Sincronizada ⏲️](#navegação-sincronizada-)
- [Abrir e Abrir Com 🚪](#abrir-e-abrir-com-)
- [Favoritos ⭐](#favoritos-)
- [Minhas Senhas São Seguras? 😈](#minhas-senhas-são-seguras-)
- [Keyring do Linux](#keyring-do-linux)
- [Configuração do KeepassXC para o termscp](#configuração-do-keepassxc-para-o-termscp)
- [Configuração ⚙️](#configuração-)
- [Armazenamento de Chave SSH 🔐](#armazenamento-de-chave-ssh-)
- [Formato do Explorador de Arquivos](#formato-do-explorador-de-arquivos)
- [Temas 🎨](#temas-)
- [Meu Tema Não Carrega 😱](#meu-tema-não-carrega-)
- [Estilos 💈](#estilos-)
- [Página de Autenticação](#página-de-autenticação)
- [Página de Transferência](#página-de-transferência)
- [Diversos](#diversos)
- [Editor de Texto ✏](#editor-de-texto-)
- [Registro de Logs 🩺](#registro-de-logs-)
- [Notificações 📫](#notificações-)
- [Observador de Arquivos 🔭](#observador-de-arquivos-)
## Uso ❓
O termscp pode ser iniciado com as seguintes opções:
`termscp [opções]... [protocol://usuário@endereço:porta:diretório-trabalho] [protocol://usuário@endereço:porta:diretório-trabalho] [diretório-trabalho-local]`
OU
`termscp [opções]... -b [nome-do-favorito] -b [nome-do-favorito] [diretório-trabalho-local]`
- `-P, --password <senha>` se o endereço for fornecido, a senha será este argumento
- `-b, --address-as-bookmark` resolve o argumento do endereço como um nome de favorito
- `-q, --quiet` Desabilita o registro de logs
- `-v, --version` Exibe informações da versão
- `-h, --help` Exibe a página de ajuda
O termscp pode ser iniciado em três modos diferentes, se nenhum argumento adicional for fornecido, ele exibirá o formulário de autenticação, onde o usuário poderá fornecer os parâmetros necessários para se conectar ao peer remoto.
Alternativamente, o usuário pode fornecer um endereço como argumento para pular o formulário de autenticação e iniciar diretamente a conexão com o servidor remoto.
Se um argumento de endereço ou nome de favorito for fornecido, você também pode definir o diretório de trabalho para o host local.
### Argumento de Endereço 🌎
O argumento de endereço tem a seguinte sintaxe:
```txt
[protocol://][username@]<address>[:port][:wrkdir]
```
Vamos ver alguns exemplos dessa sintaxe particular, pois ela é bem conveniente e você provavelmente a usará com mais frequência do que a outra...
- Conectar usando o protocolo padrão (*definido na configuração*) a 192.168.1.31; a porta, se não for fornecida, será a padrão para o protocolo selecionado (dependerá da sua configuração); o nome de usuário será o do usuário atual
```sh
termscp 192.168.1.31
```
- Conectar usando o protocolo padrão (*definido na configuração*) a 192.168.1.31; o nome de usuário é `root`
```sh
termscp root@192.168.1.31
```
- Conectar usando scp a 192.168.1.31, a porta é 4022; o nome de usuário é `omar`
```sh
termscp scp://omar@192.168.1.31:4022
```
- Conectar usando scp a 192.168.1.31, a porta é 4022; o nome de usuário é `omar`. Você começará no diretório `/tmp`
```sh
termscp scp://omar@192.168.1.31:4022:/tmp
```
#### Argumento de Endereço do AWS S3
O AWS S3 tem uma sintaxe diferente para o argumento de endereço CLI, por razões óbvias, mas tentei mantê-la o mais próxima possível do argumento de endereço genérico:
```txt
s3://<bucket-name>@<region>[:profile][:/wrkdir]
```
Exemplo:
```txt
s3://buckethead@eu-central-1:default:/assets
```
#### Argumento de endereço Kube
Caso queira se conectar ao Kube, use a seguinte sintaxe
```txt
kube://[namespace][@<cluster_url>][$</path>]
```
#### Argumento de Endereço do WebDAV
Caso você queira se conectar ao WebDAV, use a seguinte sintaxe:
```txt
http://<username>:<password>@<url></path>
```
ou, se preferir usar https:
```txt
https://<username>:<password>@<url></path>
```
#### Argumento de Endereço do SMB
O SMB tem uma sintaxe diferente para o argumento de endereço CLI, que varia se você estiver no Windows ou em outros sistemas:
**Sintaxe do Windows:**
```txt
\\[username@]<server-name>\<share>[\path\...]
```
**Sintaxe de outros sistemas:**
```txt
smb://[username@]<server-name>[:port]/<share>[/path/.../]
```
#### Como a Senha Pode Ser Fornecida 🔐
Você provavelmente notou que, ao fornecer o argumento de endereço, não há como fornecer a senha.
A senha pode ser fornecida basicamente de três maneiras quando o argumento de endereço é fornecido:
- Opção `-P, --password`: apenas use essa opção CLI fornecendo a senha. Eu desaconselho fortemente esse método, pois é muito inseguro (você pode manter a senha no histórico do shell).
- Via `sshpass`: você pode fornecer a senha via `sshpass`, por exemplo, `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31`.
- Você será solicitado a fornecer a senha: se você não usar nenhum dos métodos anteriores, será solicitado a fornecer a senha, como acontece com ferramentas mais clássicas como `scp`, `ssh`, etc.
### Subcomandos
#### Importar um Tema
Execute o termscp como `termscp theme <theme-file>`
#### Instalar a Última Versão
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
Esses parâmetros são necessários para se conectar ao AWS S3 e a outros servidores compatíveis com S3:
- AWS S3:
- **Nome do balde**
- **Região**
- *Perfil* (se não fornecido: "default")
- *Chave de acesso* (a menos que seja público)
- *Chave de acesso secreta* (a menos que seja público)
- *Token de segurança* (se necessário)
- *Token de sessão* (se necessário)
- Novo estilo de caminho: **NÃO**
- Outros endpoints S3:
- **Nome do balde**
- **Endpoint**
- *Chave de acesso* (a menos que seja público)
- *Chave de acesso secreta* (a menos que seja público)
- Novo estilo de caminho: **SIM**
### Credenciais do S3 🦊
Para se conectar a um balde do AWS S3, você obviamente precisa fornecer algumas credenciais.
Existem basicamente três maneiras de fazer isso:
Estes são os métodos para fornecer credenciais para o S3:
1. Formulário de autenticação:
1. Você pode fornecer a `access_key` (deve ser obrigatória), a `secret_access_key` (deve ser obrigatória), o `security_token` e o `session_token`.
2. Se você salvar a conexão S3 como um favorito, essas credenciais serão salvas como uma string criptografada AES-256/BASE64 no seu arquivo de favoritos (exceto para o token de segurança e o token de sessão, que são credenciais temporárias).
2. Use seu arquivo de credenciais: basta configurar a CLI da AWS via `aws configure` e suas credenciais já devem estar localizadas em `~/.aws/credentials`. Caso você esteja usando um perfil diferente de `default`, apenas forneça-o no campo de perfil no formulário de autenticação.
3. **Variáveis de ambiente**: você sempre pode fornecer suas credenciais como variáveis de ambiente. Lembre-se de que essas credenciais **sempre substituirão** as credenciais localizadas no arquivo de `credentials`. Veja como configurar o ambiente abaixo:
Estas devem sempre ser obrigatórias:
- `AWS_ACCESS_KEY_ID`: ID da chave de acesso da AWS (geralmente começa com `AKIA...`)
- `AWS_SECRET_ACCESS_KEY`: a chave de acesso secreta
Caso você tenha configurado uma segurança mais rigorosa, você *pode* precisar destes também:
- `AWS_SECURITY_TOKEN`: token de segurança
- `AWS_SESSION_TOKEN`: token de sessão
⚠️ Suas credenciais estão seguras: o termscp não manipula esses valores diretamente! Suas credenciais são consumidas diretamente pelo crate **s3**.
Se você tiver alguma preocupação com a segurança, entre em contato com o autor da biblioteca no [Github](https://github.com/durch/rust-s3) ⚠️
---
## Explorador de Arquivos 📂
Quando nos referimos a exploradores de arquivos no termscp, estamos falando dos painéis que você pode ver após estabelecer uma conexão com o remoto.
Esses painéis são basicamente três (sim, três na verdade):
- Painel do explorador local: ele é exibido à esquerda da sua tela e mostra as entradas do diretório atual do localhost.
- Painel do explorador remoto: ele é exibido à direita da sua tela e mostra as entradas do diretório atual do host remoto.
- Painel de resultados de busca: dependendo de onde você está buscando arquivos (local/remoto), ele substituirá o painel local ou o painel do explorador. Este painel mostra as entradas que correspondem à consulta de busca que você realizou.
Para trocar de painel, você precisa pressionar `<LEFT>` para mover para o painel do explorador remoto e `<RIGHT>` para voltar para o painel do explorador local. Sempre que estiver no painel de resultados da busca, você precisa pressionar `<ESC>` para sair do painel e voltar ao painel anterior.
### Atalhos de Teclado ⌨
| Tecla | Comando | Lembrete |
|----------------|----------------------------------------------------------|-------------|
| `<ESC>` | Desconectar do remoto; retornar à página de autenticação | |
| `<BACKSPACE>` | Voltar ao diretório anterior na pilha | |
| `<TAB>` | Alternar aba do explorador | |
| `<RIGHT>` | Mover para a aba do explorador remoto | |
| `<LEFT>` | Mover para a aba do explorador local | |
| `<UP>` | Mover para cima na lista selecionada | |
| `<DOWN>` | Mover para baixo na lista selecionada | |
| `<PGUP>` | Mover para cima na lista selecionada por 8 linhas | |
| `<PGDOWN>` | Mover para baixo na lista selecionada por 8 linhas | |
| `<ENTER>` | Entrar no diretório | |
| `<ESPAÇO>` | Fazer upload/download do arquivo selecionado | |
| `<BACKTAB>` | Alternar entre aba de logs e explorador | |
| `<A>` | Alternar arquivos ocultos | Todos |
| `<B>` | Ordenar arquivos por | Bubblesort?|
| `<C\|F5>` | Copiar arquivo/diretório | Copiar |
| `<D\|F7>` | Criar diretório | Diretório |
| `<E\|F8\|DEL>`| Deletar arquivo | Apagar |
| `<F>` | Buscar arquivos (suporta pesquisa com coringas) | Buscar |
| `<G>` | Ir para caminho especificado | Ir para |
| `<H\|F1>` | Mostrar ajuda | Ajuda |
| `<I>` | Mostrar informações sobre arquivo ou diretório selecionado | Informação |
| `<K>` | Criar link simbólico apontando para a entrada selecionada | Symlink |
| `<L>` | Recarregar conteúdo do diretório atual / Limpar seleção | Lista |
| `<M>` | Selecionar um arquivo | Marcar |
| `<N>` | Criar novo arquivo com o nome fornecido | Novo |
| `<O\|F4>` | Editar arquivo; veja Editor de Texto | Abrir |
| `<P>` | Abrir painel de logs | Painel |
| `<Q\|F10>` | Sair do termscp | Sair |
| `<R\|F6>` | Renomear arquivo | Renomear |
| `<S\|F2>` | Salvar arquivo como... | Salvar |
| `<T>` | Sincronizar alterações para caminho selecionado para remoto | Track |
| `<U>` | Ir para o diretório pai | Subir |
| `<V\|F3>` | Abrir arquivo com o programa padrão para o tipo de arquivo | Visualizar |
| `<W>` | Abrir arquivo com o programa fornecido | Com |
| `<X>` | Executar um comando | Executar |
| `<Y>` | Alternar navegação sincronizada | Sincronizar |
| `<Z>` | Alterar modo de arquivo | |
| `</>` | Filtrar arquivos (suporte tanto para regex quanto para coringa) | |
| `<CTRL+A>` | Selecionar todos os arquivos | |
| `<ALT+A>` | Deselecionar todos os arquivos | |
| `<CTRL+C>` | Abortir processo de transferência de arquivo | |
| `<CTRL+S>` | Obter o tamanho total do caminho selecionado | | Size |
| `<CTRL+T>` | Mostrar todos os caminhos sincronizados | Track |
### Trabalhar com múltiplos arquivos 🥷
Você pode optar por trabalhar com vários arquivos, usando estes controles simples:
- `<M>`: marcar um arquivo para seleção
- `<CTRL+A>`: selecionar todos os arquivos no diretório atual
- `<ALT+A>`: desselecionar todos os arquivos
Uma vez marcado, o arquivo será **exibido com fundo destacado** .
Ao trabalhar com seleção, apenas os arquivos selecionados serão processados, enquanto o item atualmente destacado será ignorado.
É possível trabalhar com múltiplos arquivos também no painel de resultados de busca.
Todas as ações estão disponíveis ao trabalhar com múltiplos arquivos, mas algumas funcionam de forma ligeiramente diferente. Vamos ver:
- *Copiar*: ao copiar, será solicitado o nome de destino. Com múltiplos arquivos, esse nome será o diretório de destino para todos eles.
- *Renomear*: igual a copiar, mas moverá os arquivos.
- *Salvar como*: igual a copiar, mas escreverá os arquivos nesse local.
Se você selecionar um arquivo num diretório (ex: `/home`) e mudar de diretório, ele continuará selecionado e aparecerá na **fila de transferência** no painel inferior.
Ao selecionar um arquivo, o diretório *remoto* atual é associado a ele; então, se for transferido, será enviado para esse diretório associado.
#### Exemplo
Se selecionarmos `/home/a.txt` localmente e estivermos em `/tmp` no painel remoto, depois mudarmos para `/var` e selecionarmos `/var/b.txt`, e estivermos em `/home` no painel remoto, ao transferir teremos:
- `/home/a.txt` transferido para `/tmp/a.txt`
- `/var/b.txt` transferido para `/home/b.txt`
### Navegação Sincronizada ⏲️
Quando ativada, a navegação sincronizada permitirá sincronizar a navegação entre os dois painéis.
Isso significa que, sempre que você mudar o diretório de trabalho em um painel, a mesma ação será reproduzida no outro painel. Se quiser ativar a navegação sincronizada, basta pressionar `<Y>`; pressione duas vezes para desativar. Enquanto estiver ativada, o estado da navegação sincronizada será exibido na barra de status como `ON` (Ligado).
### Abrir e Abrir Com 🚪
Os comandos para abrir e abrir com são alimentados pelo [open-rs](https://docs.rs/crate/open/1.7.0).
Ao abrir arquivos com o comando Visualizar (`<V>`), será usado o aplicativo padrão do sistema para o tipo de arquivo. Para isso, será usado o serviço padrão do sistema operacional, então certifique-se de ter pelo menos um destes instalados no seu sistema:
- Para usuários do **Windows**: você não precisa se preocupar, pois o crate usará o comando `start`.
- Para usuários do **MacOS**: também não é necessário se preocupar, pois o crate usará `open`, que já está instalado no seu sistema.
- Para usuários do **Linux**: um dos seguintes deve estar instalado:
- *xdg-open*
- *gio*
- *gnome-open*
- *kde-open*
- Para usuários do **WSL**: *wslview* é necessário, você deve instalar [wslu](https://github.com/wslutilities/wslu).
> Pergunta: Posso editar arquivos remotos usando o comando de visualização?
> Resposta: Não, pelo menos não diretamente do "painel remoto". Você deve baixá-lo para um diretório local primeiro, porque quando você abre um arquivo remoto, ele é baixado para um diretório temporário, mas não há como criar um observador para o arquivo para verificar quando o programa que você usou para abri-lo foi fechado, então o termscp não pode saber quando você terminou de editar o arquivo.
---
## Favoritos ⭐
No termscp é possível salvar hosts favoritos, que podem ser carregados rapidamente a partir do layout principal do termscp.
O termscp também salvará os últimos 16 hosts aos quais você se conectou.
Esse recurso permite que você carregue todos os parâmetros necessários para se conectar a um determinado host remoto, simplesmente selecionando o favorito na aba abaixo do formulário de autenticação.
Os favoritos serão salvos, se possível, em:
- `$HOME/.config/termscp/` no Linux/BSD
- `$HOME/Library/Application Support/termscp` no MacOS
- `FOLDERID_RoamingAppData\termscp\` no Windows
Para os favoritos apenas (isso não se aplica aos hosts recentes), também é possível salvar a senha usada para autenticar. A senha não é salva por padrão e deve ser especificada no prompt ao salvar um novo favorito.
Se você estiver preocupado com a segurança da senha salva para seus favoritos, por favor, leia o [capítulo abaixo 👀](#minhas-senhas-são-seguras-).
Para criar um novo favorito, siga estas etapas:
1. Digite no formulário de autenticação os parâmetros para se conectar ao seu servidor remoto
2. Pressione `<CTRL+S>`
3. Digite o nome que deseja dar ao favorito
4. Escolha se deseja lembrar da senha ou não
5. Pressione `<ENTER>` para enviar
Sempre que quiser usar a conexão salva anteriormente, basta pressionar `<TAB>` para navegar para a lista de favoritos e carregar os parâmetros do favorito no formulário pressionando `<ENTER>`.
![Favoritos](https://github.com/veeso/termscp/blob/main/assets/images/bookmarks.gif?raw=true)
### Minhas Senhas São Seguras? 😈
Claro 😉.
Como já mencionado, os favoritos são salvos no diretório de configuração juntamente com as senhas. As senhas, obviamente, não são texto simples, elas são criptografadas com **AES-128**. Isso as torna seguras? Absolutamente! (exceto para usuários de BSD e WSL 😢)
No **Windows**, **Linux** e **MacOS**, a chave usada para criptografar senhas é armazenada, se possível (e deve ser), respectivamente no *Windows Vault*, no *sistema keyring* e no *Keychain*. Isso é realmente super seguro e é gerenciado diretamente pelo seu sistema operacional.
❗ Por favor, note que se você é um usuário de Linux, seria melhor ler o [capítulo abaixo 👀](#keyring-do-linux), porque o keyring pode não estar habilitado ou suportado no seu sistema!
Por outro lado, no *BSD* e no *WSL*, a chave usada para criptografar suas senhas é armazenada em seu disco (em `$HOME/.config/termscp`). Ainda é possível recuperar a chave para descriptografar as senhas. Felizmente, a localização da chave garante que ela não possa ser lida por outros usuários diferentes de você, mas sim, eu ainda não salvaria a senha para um servidor exposto na internet 😉.
#### Keyring do Linux
Todos nós amamos o Linux por causa da liberdade que ele oferece aos usuários. Você pode basicamente fazer o que quiser como usuário de Linux, mas isso também tem alguns contras, como o fato de muitas vezes não haver aplicativos padrão em diferentes distribuições. E isso também envolve o keyring.
Isso significa que no Linux pode não haver um keyring instalado no seu sistema. Infelizmente, a biblioteca que usamos para trabalhar com o armazenamento de chaves requer um serviço que expõe `org.freedesktop.secrets` no D-BUS, e o pior é que há apenas dois serviços que o expõem.
- ❗ Se você usa GNOME como ambiente de desktop (por exemplo, usuários do Ubuntu), já deve estar bem, pois o keyring já é fornecido pelo `gnome-keyring` e tudo deve estar funcionando.
- ❗ Para usuários de outros ambientes de desktop, há um programa legal que você pode usar para obter um keyring, que é o [KeepassXC](https://keepassxc.org/), que eu uso na minha instalação Manjaro (com KDE) e funciona bem. O único problema é que você precisa configurá-lo para ser usado junto com o termscp (mas é bastante simples). Para começar com KeepassXC, leia mais [aqui](#configuração-do-keepassxc-para-o-termscp).
- ❗ E se você não quiser instalar nenhum desses serviços? Bem, não tem problema! **termscp continuará funcionando normalmente**, mas salvará a chave em um arquivo, como normalmente faz para BSD e WSL.
##### Configuração do KeepassXC para o termscp
Siga estas etapas para configurar o KeepassXC para o termscp:
1. Instale o KeepassXC
2. Vá para "ferramentas" > "configurações" na barra de ferramentas
3. Selecione "Integração do Serviço Secreto" e ative "Habilitar Integração do Serviço Secreto do KeepassXC"
4. Crie um banco de dados, se você ainda não tiver um: na barra de ferramentas "Banco de dados" > "Novo banco de dados"
5. Na barra de ferramentas: "Banco de dados" > "Configurações do banco de dados"
6. Selecione "Integração do Serviço Secreto" e ative "Expor entradas sob este grupo"
7. Selecione o grupo na lista onde deseja que o segredo do termscp seja mantido. Lembre-se de que esse grupo pode ser usado por qualquer outro aplicativo para armazenar segredos via DBUS.
---
## Configuração ⚙️
O termscp suporta alguns parâmetros definidos pelo usuário, que podem ser definidos na configuração.
Por baixo dos panos, o termscp tem um arquivo TOML e alguns outros diretórios onde todos os parâmetros serão salvos, mas não se preocupe, você não precisará tocar em nenhum desses arquivos manualmente, pois fiz com que fosse possível configurar o termscp completamente a partir de sua interface de usuário.
Assim como para os favoritos, o termscp só requer que esses caminhos estejam acessíveis:
- `$HOME/.config/termscp/` no Linux/BSD
- `$HOME/Library/Application Support/termscp` no MacOs
- `FOLDERID_RoamingAppData\termscp\` no Windows
Para acessar a configuração, basta pressionar `<CTRL+C>` a partir da tela inicial do termscp.
Estes parâmetros podem ser alterados:
- **Editor de Texto**: o editor de texto a ser usado. Por padrão, o termscp encontrará o editor padrão para você; com essa opção, você pode forçar um editor a ser usado (por exemplo, `vim`). **Também são suportados editores GUI**, a menos que eles `nohup` do processo pai.
- **Protocolo Padrão**: o protocolo padrão é o valor padrão para o protocolo de transferência de arquivos a ser usado no termscp. Isso se aplica à página de login e ao argumento CLI do endereço.
- **Exibir Arquivos Ocultos**: selecione se os arquivos ocultos devem ser exibidos por padrão. Você ainda poderá decidir se deseja exibir ou não arquivos ocultos em tempo de execução pressionando `A`.
- **Verificar atualizações**: se definido como `yes`, o termscp buscará a API do Github para verificar se há uma nova versão do termscp disponível.
- **Prompt ao substituir arquivos existentes?**: Se definido como `yes`, o termscp pedirá confirmação sempre que uma transferência de arquivos causaria a substituição de um arquivo existente no host de destino.
- **Agrupar Diretórios**: selecione se os diretórios devem ser agrupados ou não nos exploradores de arquivos. Se `Display first` for selecionado, os diretórios serão ordenados usando o método configurado, mas exibidos antes dos arquivos; se `Display last` for selecionado, eles serão exibidos depois.
- **Sintaxe do formatador de arquivos remotos**: sintaxe para exibir informações de arquivo para cada arquivo no explorador remoto. Veja [Formato do Explorador de Arquivos](#formato-do-explorador-de-arquivos)
- **Sintaxe do formatador de arquivos locais**: sintaxe para exibir informações de arquivo para cada arquivo no explorador local. Veja [Formato do Explorador de Arquivos](#formato-do-explorador-de-arquivos)
- **Habilitar notificações?**: Se definido como `Yes`, as notificações serão exibidas.
- **Notificações: tamanho mínimo para transferência**: se o tamanho da transferência for maior ou igual ao valor especificado, as notificações para a transferência serão exibidas. Os valores aceitos estão no formato `{UNSIGNED} B/KB/MB/GB/TB/PB`.
- **Caminho da configuração SSH**: define o arquivo de configuração SSH a ser usado ao se conectar a um servidor SCP/SFTP. Se não definido (vazio), nenhum arquivo será usado. Você pode especificar um caminho começando com `~` para indicar o caminho inicial (por exemplo, `~/.ssh/config`). Os parâmetros suportados pelo termscp estão especificados [AQUI](https://github.com/veeso/ssh2-config#exposed-attributes).
### Armazenamento de Chave SSH 🔐
Além da configuração, o termscp também oferece um recurso **essencial** para **clientes SFTP/SCP**: o armazenamento de chave SSH.
Você pode acessar o armazenamento de chaves SSH na configuração, indo para a aba `Chaves SSH`. Uma vez lá, você pode:
- **Adicionar uma nova chave**: basta pressionar `<CTRL+N>` e você será solicitado a criar uma nova chave. Forneça o nome do host/endereço IP e o nome de usuário associado à chave e, finalmente, um editor de texto será aberto: cole a **chave SSH PRIVADA** no editor de texto, salve e saia.
- **Remover uma chave existente**: apenas pressione `<DEL>` ou `<CTRL+E>` na chave que você deseja remover para deletar a chave do termscp permanentemente.
- **Editar uma chave existente**: basta pressionar `<ENTER>` na chave que você deseja editar para alterar a chave privada.
> Pergunta: Espere, minha chave privada está protegida com senha, posso usá-la?
> Resposta: Claro que sim. A senha fornecida para autenticação no termscp é válida tanto para autenticação por nome de usuário/senha quanto para autenticação por chave RSA.
### Formato do Explorador de Arquivos
É possível, através da configuração, definir um formato personalizado para o explorador de arquivos. Isso é possível tanto para o host local quanto para o remoto, para que você possa ter duas sintaxes diferentes em uso. Esses campos, com nome `File formatter syntax (local)` e `File formatter syntax (remote)`, definirão como as entradas de arquivos serão exibidas no explorador de arquivos.
A sintaxe para o formatador é a seguinte `{KEY1}... {KEY2:LENGTH}... {KEY3:LENGTH:EXTRA} {KEYn}...`.
Cada chave entre colchetes será substituída pelo atributo relacionado, enquanto tudo fora dos colchetes permanecerá inalterado.
- O nome da chave é obrigatório e deve ser uma das chaves abaixo.
- O comprimento descreve o espaço reservado para exibir o campo. Atributos estáticos não suportam esse recurso (GRUPO, PEX, TAMANHO, USUÁRIO).
- O Extra é suportado apenas por alguns parâmetros e é uma opção adicional. Veja as chaves para verificar se o extra é suportado.
Estas são as chaves suportadas pelo formatador:
- `ATIME`: Última vez de acesso (com sintaxe padrão `%b %d %Y %H:%M`); O Extra pode ser fornecido como a sintaxe de tempo (por exemplo, `{ATIME:8:%H:%M}`).
- `CTIME`: Tempo de criação (com sintaxe `%b %d %Y %H:%M`); O Extra pode ser fornecido como a sintaxe de tempo (por exemplo, `{CTIME:8:%H:%M}`).
- `GROUP`: Grupo do proprietário.
- `MTIME`: Última modificação (com sintaxe `%b %d %Y %H:%M`); O Extra pode ser fornecido como a sintaxe de tempo (por exemplo, `{MTIME:8:%H:%M}`).
- `NAME`: Nome do arquivo (pastas entre a raiz e os primeiros ancestrais são omitidas se forem maiores que o comprimento).
- `PATH`: Caminho absoluto do arquivo (pastas entre a raiz e os primeiros ancestrais são omitidas se forem maiores que o comprimento).
- `PEX`: Permissões do arquivo (formato UNIX).
- `SIZE`: Tamanho do arquivo (omitido para diretórios).
- `SYMLINK`: Link simbólico (se houver `-> {FILE_PATH}`).
- `USER`: Nome do proprietário.
Se deixado vazio, será usada a sintaxe padrão do formatador: `{NAME:24} {PEX} {USER} {SIZE} {MTIME:17:%b %d %Y %H:%M}`.
---
## Temas 🎨
O termscp oferece a você um recurso incrível: a possibilidade de definir as cores para vários componentes no aplicativo.
Se você deseja personalizar o termscp, há duas maneiras disponíveis para fazer isso:
- A partir do **menu de configuração**
- Importando um **arquivo de tema**
Para criar sua própria personalização no termscp, tudo o que você precisa fazer é entrar na configuração a partir da atividade de autenticação, pressionar `<CTRL+C>` e depois `<TAB>` duas vezes. Agora você deve ter se movido para o painel de `themes`.
Aqui você pode se mover com `<UP>` e `<DOWN>` para alterar o estilo que deseja alterar, como mostrado no gif abaixo:
![Temas](https://github.com/veeso/termscp/blob/main/assets/images/themes.gif?raw=true)
O termscp suporta tanto a sintaxe tradicional de hexadecimal explícito (`#rrggbb`) quanto rgb `rgb(r, g, b)` para fornecer cores, mas também **[cores CSS](https://www.w3schools.com/cssref/css_colors.asp)** (como `crimson`) são aceitas 😉. Há também uma palavra-chave especial, que é `Default`. Default significa que a cor usada será a cor padrão de primeiro plano ou plano de fundo, dependendo da situação (primeiro plano para textos e linhas, plano de fundo para, bem, adivinhe).
Como mencionado antes, você também pode importar arquivos de temas. Você pode se inspirar ou usar diretamente um dos temas fornecidos junto com o termscp, localizado no diretório `themes/` deste repositório, e importá-los executando o termscp como `termscp -t <arquivo-do-tema>`. Se tudo correu bem, ele deve informar que o tema foi importado com sucesso.
### Meu Tema Não Carrega 😱
Isso provavelmente se deve a uma atualização recente que quebrou o tema. Sempre que eu adiciono uma nova chave aos temas, o tema salvo não será carregado. Para corrigir esse problema, existem duas soluções rápidas:
1. Recarregar o tema: sempre que eu lançar uma atualização, também corrigirei os "temas oficiais", então você só precisará baixá-lo novamente do repositório e reimportar o tema usando a opção `-t`.
```sh
termscp -t <theme.toml>
```
2. Corrigir seu tema: se você estiver usando um tema personalizado, você pode editá-lo via `vim` e adicionar a chave que está faltando. O tema está localizado em `$CONFIG_DIR/termscp/theme.toml`, onde `$CONFIG_DIR` é:
- FreeBSD/GNU-Linux: `$HOME/.config/`
- MacOs: `$HOME/Library/Application Support`
- Windows: `%appdata%`
❗ As chaves que faltam são relatadas no CHANGELOG sob `BREAKING CHANGES` para a versão que você acabou de instalar.
### Estilos 💈
Você pode encontrar na tabela abaixo a descrição para cada campo de estilo.
Por favor, note que **estilos não se aplicam à página de configuração**, para torná-la sempre acessível no caso de você bagunçar tudo.
#### Página de Autenticação
| Chave | Descrição |
|-----------------|----------------------------------------------|
| auth_address | Cor do campo de entrada para endereço IP |
| auth_bookmarks | Cor do painel de favoritos |
| auth_password | Cor do campo de entrada para senha |
| auth_port | Cor do campo de entrada para número da porta |
| auth_protocol | Cor do grupo de rádio para protocolo |
| auth_recents | Cor do painel de recentes |
| auth_username | Cor do campo de entrada para nome de usuário |
#### Página de Transferência
| Chave | Descrição |
|--------------------------------------|---------------------------------------------------------------------------------|
| transfer_local_explorer_background | Cor de fundo do explorador do localhost |
| transfer_local_explorer_foreground | Cor de primeiro plano do explorador do localhost |
| transfer_local_explorer_highlighted | Cor da borda e realce do explorador do localhost |
| transfer_remote_explorer_background | Cor de fundo do explorador remoto |
| transfer_remote_explorer_foreground | Cor de primeiro plano do explorador remoto |
| transfer_remote_explorer_highlighted | Cor da borda e realce do explorador remoto |
| transfer_log_background | Cor de fundo do painel de logs |
| transfer_log_window | Cor da janela para o painel de logs |
| transfer_progress_bar_partial | Cor parcial da barra de progresso |
| transfer_progress_bar_total | Cor total da barra de progresso |
| transfer_status_hidden | Cor para a etiqueta "oculto" na barra de status |
| transfer_status_sorting | Cor para a etiqueta "ordenando" na barra de status; aplica-se também ao diálogo de ordenação de arquivos |
| transfer_status_sync_browsing | Cor para a etiqueta "navegação sincronizada" na barra de status |
#### Diversos
Estes estilos se aplicam a diferentes partes do aplicativo.
| Chave | Descrição |
|-----------------------------|------------------------------------------------|
| misc_error_dialog | Cor para mensagens de erro |
| misc_info_dialog | Cor para diálogos de informações |
| misc_input_dialog | Cor para diálogos de entrada (como copiar arquivo) |
| misc_keys | Cor do texto para teclas de atalho |
| misc_quit_dialog | Cor para diálogos de saída |
| misc_save_dialog | Cor para diálogos de salvar |
| misc_warn_dialog | Cor para diálogos de aviso |
---
## Editor de Texto ✏
O termscp possui, como você deve ter notado, muitos recursos, um deles é a possibilidade de visualizar e editar arquivos de texto. Não importa se o arquivo está localizado no host local ou no host remoto, o termscp oferece a possibilidade de abrir um arquivo no seu editor de texto favorito.
Caso o arquivo esteja localizado no host remoto, ele será primeiro baixado para o seu diretório temporário e, **somente** se alterações forem feitas no arquivo, ele será re-enviado para o host remoto. O termscp verifica se você fez alterações no arquivo verificando o último tempo de modificação do arquivo.
> ❗ Apenas um lembrete: **você só pode editar arquivos de texto**; arquivos binários não são suportados.
---
## Registro de Logs 🩺
O termscp escreve um arquivo de log para cada sessão, que é gravado em:
- `$HOME/.cache/termscp/termscp.log` no Linux/BSD
- `$HOME/Library/Caches/termscp/termscp.log` no MacOs
- `FOLDERID_LocalAppData\termscp\termscp.log` no Windows
o log não será rotacionado, mas será truncado após cada execução do termscp, então se você quiser relatar um problema e anexar seu arquivo de log, lembre-se de salvar o arquivo de log em um local seguro antes de usar o termscp novamente. O registro por padrão é feito no nível *INFO*, então não é muito detalhado.
Se você quiser enviar um problema, por favor, se puder, reproduza o problema com o nível definido como `TRACE`, para isso, inicie o termscp com a opção CLI `-D`.
Sei que você pode ter algumas perguntas sobre arquivos de log, então fiz um tipo de perguntas e respostas:
> Não quero registros, posso desativá-los?
Sim, você pode. Basta iniciar o termscp com a opção `-q ou --quiet`. Você pode aliasar o termscp para tornar isso persistente. Lembre-se de que os registros são usados para diagnosticar problemas, então, como atrás de todo projeto de código aberto deve sempre haver esse tipo de ajuda mútua, manter os arquivos de log pode ser sua maneira de apoiar o projeto 😉. Não quero que você se sinta culpado, mas só estou dizendo.
> O registro é seguro?
Se você estiver preocupado com a segurança, o arquivo de log não contém nenhuma senha em texto simples, então não se preocupe e expõe as mesmas informações que o arquivo irmão `bookmarks` relata.
## Notificações 📫
O termscp enviará notificações da área de trabalho para estes tipos de eventos:
- Em **Transferência concluída**: A notificação será enviada quando uma transferência for concluída com sucesso.
- ❗ A notificação será exibida apenas se o tamanho total da transferência for pelo menos o especificado em `Notifications: minimum transfer size` na configuração.
- Em **Transferência falhou**: A notificação será enviada quando uma transferência falhar devido a um erro.
- ❗ A notificação será exibida apenas se o tamanho total da transferência for pelo menos o especificado em `Notifications: minimum transfer size` na configuração.
- Em **Atualização disponível**: Sempre que uma nova versão do termscp estiver disponível, uma notificação será exibida.
- Em **Atualização instalada**: Sempre que uma nova versão do termscp for instalada, uma notificação será exibida.
- Em **Falha na atualização**: Sempre que a instalação da atualização falhar, uma notificação será exibida.
❗ Se você prefere manter as notificações desativadas, basta entrar na configuração e definir `Enable notifications?` para `No` 😉.
❗ Se quiser alterar o tamanho mínimo para exibir notificações, você pode mudar o valor na configuração com a chave `Notifications: minimum transfer size` e ajustá-lo ao que for melhor para você 🙂.
---
## Observador de Arquivos 🔭
O observador de arquivos permite que você configure uma lista de caminhos para sincronizar com os hosts remotos.
Isso significa que, sempre que uma alteração no sistema de arquivos local for detectada no caminho sincronizado, a alteração será automaticamente relatada para o caminho do host remoto configurado, dentro de 5 segundos.
Você pode definir quantos caminhos desejar para sincronizar:
1. Coloque o cursor no explorador local no diretório/arquivo que deseja manter sincronizado.
2. Vá para o diretório para o qual deseja que as alterações sejam relatadas no host remoto.
3. Pressione `<T>`.
4. Responda `<YES>` na janela pop-up.
Para desfazer a observação, basta pressionar `<T>` no caminho local sincronizado (ou em qualquer um de seus subdiretórios)
OU você pode simplesmente pressionar `<CTRL+T>` e pressionar `<ENTER>` no caminho sincronizado que deseja desfazer a observação.
Estas alterações serão relatadas para o host remoto:
- Novos arquivos, alterações em arquivos.
- Arquivo movido/renomeado.
- Arquivo removido/desvinculado.
> ❗ O observador funciona apenas em uma direção (local > remoto). Não é possível sincronizar automaticamente as alterações do host remoto para o local.

View File

@@ -1,26 +1,34 @@
# termscp
<p align="center">
<img src="/assets/images/termscp.svg" width="256" height="256" />
<img src="/assets/images/termscp.svg" alt="logo" width="256" height="256" />
</p>
<p align="center">~ 功能丰富的终端文件传输 ~</p>
<p align="center">~ 功能丰富的终端文件传输工具 ~</p>
<p align="center">
<a href="https://veeso.github.io/termscp/" target="_blank">网站</a>
<a href="https://termscp.veeso.dev" target="_blank">网站</a>
·
<a href="https://veeso.github.io/termscp/#get-started" target="_blank">安装</a>
<a href="https://termscp.veeso.dev/get-started.html" target="_blank">安装</a>
·
<a href="https://veeso.github.io/termscp/#user-manual" target="_blank">用户手册</a>
<a href="https://termscp.veeso.dev/user-manual.html" target="_blank">用户手册</a>
</p>
<p align="center">
<a href="https://github.com/veeso/termscp"
><img
height="20"
src="/assets/images/flags/us.png"
src="/assets/images/flags/gb.png"
alt="English"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/pt-BR/README.md"
><img
height="20"
src="/assets/images/flags/br.png"
alt="Brazilian Portuguese"
/></a>
&nbsp;
<a
href="https://github.com/veeso/termscp/blob/main/docs/de/README.md"
><img
@@ -62,8 +70,8 @@
/></a>
</p>
<p align="center"><a href="https://veeso.github.io/" target="_blank">@veeso</a> 开发</p>
<p align="center">当前版本: 0.8.0 (06/01/2022)</p>
<p align="center"><a href="https://veeso.me/" target="_blank">@veeso</a> 开发</p>
<p align="center">当前版本: 0.19.0 11/11/2025</p>
<p align="center">
<a href="https://opensource.org/licenses/MIT"
@@ -118,60 +126,61 @@
src="https://coveralls.io/repos/github/veeso/termscp/badge.svg"
alt="Coveralls"
/></a>
<a href="https://docs.rs/termscp"
><img
src="https://docs.rs/termscp/badge.svg"
alt="Docs"
/></a>
</p>
---
## 关于 termscp 🖥
termscp 是一个功能丰富的终端文件传输和浏览器,支持 SCP/SFTP/FTP/S3。 所以基本上是一个带有 TUI 的终端实用程序,用于连接到远程服务器检索和上传文件并与本地文件系统进行交互。
它与 **Linux**、**MacOS**、**FreeBSD** 和 **Windows** 兼容。
termscp 是一个功能丰富的终端文件浏览和传输工具,支持 SCP/SFTP/FTP/Kube/S3/WebDAV。 作为一个带有 TUI 的命令行工具,它可以连接到远程服务器进行文件检索和上传,并能够与本地文件系统进行交互。
兼容 **Linux**、**MacOS**、**FreeBSD** 和 **Windows** 操作系统。
![Explorer](/assets/images/explorer.gif)
---
## 特 🎁
## 特 🎁
- 📁 不同的通讯协议
- 📁 支持多种通信协议
- **SFTP**
- **SCP**
- **FTP** and **FTPS**
- **Aws S3**
- 🖥 使用方便的 UI 在远程和本地机器文件系统上探索和操作
- **Kube**
- **S3**
- **SMB**
- **WebDAV**
- 🖥 使用便捷的 UI 在远程和本地文件系统上浏览和操作
- 创建、删除、重命名、搜索、查看和编辑文件
- ⭐ 通过内置书签最近连接连接到您最喜欢的主机
- ⭐ 通过内置书签”和“最近连接”快速连接到您的主机
- 📝 使用您喜欢的应用程序查看和编辑文件
- 💁 使用 SSH 密钥和用户名/密码进行 SFTP/SCP 身份验证
- 🐧 Windows、Linux、FreeBSD 和 MacOS 兼容
- 🎨 让它成为你的
- 🐧 兼容 Windows、Linux、FreeBSD 和 MacOS 操作系统
- 🎨 丰富的个性化设置
- 主题
- 自定义文件浏览器格式
-定制的文本编辑器
-定制的文件排序
- 和许多其他参数...
- 📫 传输大文件时通过桌面通知获得通知
-选择的文本编辑器
-选择的文件排序
- 探索更多功能...
- 📫 传输大文件时通过桌面通知获得提醒
- 🔭 与远程主机文件更改保持同步
- 🔐 将密码保存在操作系统密钥保管库中
- 🦀 Rust 动力
- 👀 开发时注意性能
- 🦄 频繁的精彩更新
- 🦀 Rust 提供强力支持
- 👀 开发时更注重性能
- 🦄 快速且精彩迭代
---
## 开始 🚀
如果您正在考虑安装termscp,我要感谢您💜! 希望你会喜欢termscp
非常荣幸您能考虑安装termscp💜 希望你会喜欢termscp
如果您想为此项目做出贡献,请不要忘记查看我们的贡献指南。 [阅读更多](../../CONTRIBUTING.md)
如果您是 Linux、FreeBSD 或 MacOS 用户,这个简单的 shell 脚本将使用单个命令在您的系统上安装 termscp
如果您是 Linux、FreeBSD 或 MacOS 用户,使用以下简单的 shell 脚本通过单行指令在您的系统上安装 termscp
```sh
curl --proto '=https' --tlsv1.2 -sSLf "https://git.io/JBhDb" | sh
curl -sSLf http://get-termscp.veeso.dev | sh
```
如果您是 Windows 用户,则可以使用 [Chocolatey](https://chocolatey.org/) 安装 termscp
@@ -180,24 +189,26 @@ curl --proto '=https' --tlsv1.2 -sSLf "https://git.io/JBhDb" | sh
choco install termscp
```
如需更多信息或其他平台,请访问 [veeso.github.io](https://veeso.github.io/termscp/#get-started) 查看所有安装方法。
如需更多信息或其他平台支持,请访问 [termscp.veeso.dev](https://termscp.veeso.dev/termscp/get-started.html) 查看所有安装方法。
⚠️ 如果您正在寻找如何更新 termscp 只需从 CLI 运行 termscp `(sudo) termscp --update` ⚠️
### 要求
### 依赖
- **Linux** 用户:
- libssh
- libdbus-1
- pkg-config
- libsmbclient
- **FreeBSD** 用户:
- libssh
- dbus
- pkgconf
- libsmbclient
### 可选要求 ✔️
### 可选 ✔️
这些要求不是运行 termscp 的强制要求,而是要享受它的所有功能
通过执行以下操作以享受软件的完整功能,但不做强制要求
- **Linux/FreeBSD** 用户:
-`V` **打开** 文件(至少其中之一)
@@ -215,11 +226,11 @@ choco install termscp
## 支持我 ☕
如果您喜欢 termscp 并且希望看到该项目不断发展和改进,请考虑在 **Buy me a coffee**捐款以支持我🥳
如果您喜欢 termscp 并且希望看到该项目不断发展和改进,请考虑在 **Buy me a coffee**赞赏以支持我🥳
[![ko-fi](https://img.shields.io/badge/Ko--fi-F16061?style=for-the-badge&logo=ko-fi&logoColor=white)](https://ko-fi.com/veeso)
或者,如果您愿意,您也可以在 PayPal 上捐款
或者,如果您愿意,您也可以在 PayPal 上赞赏我
[![PayPal](https://img.shields.io/badge/PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white)](https://www.paypal.me/chrisintin)
@@ -227,28 +238,27 @@ choco install termscp
## 用户手册和文档 📚
用户手册可以在[termscp的网站](https://veeso.github.io/termscp/#user-manual)上找到 或者在[Github](man.md)上。
开发者文档可以在 <https://docs.rs/termscp> 的 Rust Docs 上找到。
用户手册可以在[termscp的网站](https://termscp.veeso.dev/termscp/user-manual.html)或者在[Github](man.md)上找到
---
## 贡献和问题 🤝🏻
欢迎贡献、错误报告、新功能和问题! 😉
如果您有任何问题或疑虑或者您想建议新功能或者您只想改进termscp请随时打开问题或 PR。
欢迎贡献、bug报告、新功能和问题! 😉
如果您有任何问题或困惑或者您想建议新功能或者您只是想改进termscp请随时打开 issue 或 PR。
请遵循 [我们的贡献指南](../../CONTRIBUTING.md)
---
## 更日志 ⏳
## 更日志 ⏳
查看termscp的更新日志 [这里](../../CHANGELOG.md)
查看termscp的 [更新日志](../../CHANGELOG.md)
---
## 供电 💪
## 支持 💪
termscp 由这些很棒的项目提供支持:
@@ -262,16 +272,16 @@ termscp 由这些很棒的项目提供支持:
- [self_update](https://github.com/jaemk/self_update)
- [ssh2-rs](https://github.com/alexcrichton/ssh2-rs)
- [suppaftp](https://github.com/veeso/suppaftp)
- [tui-rs](https://github.com/fdehau/tui-rs)
- [ratatui](https://github.com/ratatui-org/ratatui)
- [tui-realm](https://github.com/veeso/tui-realm)
- [whoami](https://github.com/libcala/whoami)
- [wildmatch](https://github.com/becheran/wildmatch)
---
## 画廊 🎬
## 演示 🎬
>
> 首页
![Auth](/assets/images/auth.gif)
@@ -289,8 +299,8 @@ termscp 由这些很棒的项目提供支持:
---
## 执照 📃
## 许可协议 📃
“termscp” MIT 许可下获得许可。
“termscp”使用 MIT 许可。
您可以阅读整个许可证 [这里](../../LICENSE)
您可以阅读整个 [许可证](../../LICENSE)

View File

@@ -4,11 +4,20 @@
- [用法](#用法)
- [地址参数](#地址参数)
- [AWS S3 地址参数](#aws-s3-地址参数)
- [Kube 地址参数](#kube-地址参数)
- [WebDAV 地址参数](#webdav-地址参数)
- [SMB 地址参数](#smb-地址参数)
- [如何输入密码](#如何输入密码)
- [Aws S3 凭证](#aws-s3-凭证)
- [子命令](#子命令)
- [导入主题](#导入主题)
- [安装最新版本](#安装最新版本)
- [导入 SSH 主机](#导入-ssh-主机)
- [S3 连接参数](#s3-连接参数)
- [Aws S3 凭证](#aws-s3-凭证)
- [文件浏览](#文件浏览)
- [快捷键](#快捷键)
- [处理多个文件](#处理多个文件)
- [操作多个文件 🥷](#操作多个文件-)
- [示例](#示例)
- [同步浏览](#同步浏览)
- [打开/打开方式](#打开打开方式)
- [书签](#书签)
@@ -27,17 +36,21 @@
- [文本编辑器](#文本编辑器)
- [日志](#日志)
- [通知](#通知)
- [文件观察者🔭](#文件观察者)
## 用法
termscp启动时可以使用以下选项:
`termscp [options]... [protocol://user@address:port:wrkdir] [local-wrkdir]`
`termscp [options]... [protocol://user@address:port:wrkdir] [protocol://user@address:port:wrkdir] [local-wrkdir]`
或作为
`termscp [options]... -b [bookmark-name] -b [bookmark-name] [local-wrkdir]`
- `-P, --password <password>` 登陆密码
- `-c, --config` 打开termscp时打开配置页面
- `-b, --address-as-bookmark` 将地址参数解析为书签名称
- `-q, --quiet` 禁用日志
- `-t, --theme <path>` 导入自定义主题
- `-v, --version` 打印版本信息
- `-h, --help` 打开帮助
@@ -95,6 +108,43 @@ s3://<bucket-name>@<region>[:profile][:/wrkdir]
s3://buckethead@eu-central-1:default:/assets
```
#### Kube 地址参数
如果您想连接到 Kube请使用以下语法
```txt
kube://[namespace][@<cluster_url>][$</path>]
```
#### WebDAV 地址参数
如果您想要连接到 WebDAV请使用以下语法
```txt
http://<username>:<password>@<url></path>
或者如果您想要使用 https
```
```txt
https://<username>:<password>@<url></path>
```
#### SMB 地址参数
SMB 对 CLI 地址参数有不同的语法,无论您是在 Windows 还是其他系统上,这都是不同的:
**Windows** 句法:
```txt
\\[username@]<server-name>\<share>[\path\...]
```
**其他系统** 句法:
```txt
smb://[username@]<server-name>[:port]/<share>[/path/.../]
```
#### 如何输入密码
你可能已经注意到url参数中没有办法直接附加密码你可以通过以下三种方式提供密码
@@ -103,9 +153,44 @@ s3://buckethead@eu-central-1:default:/assets
- 通过 `sshpass`: 你可以通过 `sshpass` 传入密码, 例如: `sshpass -f ~/.ssh/topsecret.key termscp cvisintin@192.168.1.31`
- 提示输入密码:如果你不使用前面的任何方法,你会被提示输入密码,就像 `scp`、`ssh` 等比较经典的工具上一样。
### 子命令
#### 导入主题
以 termscp theme <theme-file> 的方式运行 termscp。
#### 安装最新版本
以 termscp update 的方式运行 termscp。
#### 导入 SSH 主机
以 `termscp import-ssh-hosts [ssh-config-file]` 的方式运行 termscp。
从指定的 SSH 配置文件中导入所有主机(如果未提供,则使用 `~/.ssh/config`)作为 termscp 中的书签。身份文件也会作为 SSH 密钥导入到 termscp 中。
---
## Aws S3 凭证
## S3 连接参数
这些参数是连接到 aws s3 和其他 s3 兼容服务器所必需的:
- AWS S3:
- **bucket name**
- **region**
- *profile* (如果未提供“default”)
- *access key* (除非公开)
- *secret access key* (除非公开)
- *security token* (如果需要的话)
- *session token* (如果需要的话)
- new path style: **NO**
- 其他 S3 端点:
- **bucket name**
- **endpoint**
- *access key* (如果需要的话)
- *secret access key* (如果需要的话)
- new path style: **YES**
### Aws S3 凭证
为了连接到 Aws S3 存储桶,您显然必须提供一些凭据。
因此,您可以通过以下方式为 s3 提供凭据:
@@ -160,37 +245,64 @@ termscp中的文件资源管理器是指你与远程建立连接后可以看到
| `<BACKTAB>` | 在日志面板和管理器面板之间切换 | |
| `<A>` | 是否显示隐藏文件 | All |
| `<B>` | 按..排序 | Bubblesort? |
| `<C|F5>` | 复制文件(夹) | Copy |
| `<D|F7>` | 创建文件夹 | Directory |
| `<E|F8|DEL>` | 删除文件 | Erase |
| `<C\|F5>` | 复制文件(夹) | Copy |
| `<D\|F7>` | 创建文件夹 | Directory |
| `<E\|F8\|DEL>` | 删除文件 | Erase |
| `<F>` | 文件搜索 (支持通配符) | Find |
| `<G>` | 跳转到指定路径 | Go to |
| `<H|F1>` | 显示帮助 | Help |
| `<H\|F1>` | 显示帮助 | Help |
| `<I>` | 显示选中文件(夹)信息 | Info |
| `<K>` | 创建指向当前选定条目的符号链接 | symlinK |
| `<L>` | 刷新当前目录列表 / 清除选中状态 | List |
| `<M>` | 选中文件 | Mark |
| `<N>` | 使用键入的名称新建文件 | New |
| `<O|F4>` | 编辑文件;参考文本编辑器文档 | Open |
| `<Q|F10>` | 退出termscp | Quit |
| `<R|F7>` | 重命名文件 | Rename |
| `<S|F2>` | 另存为... | Save |
| `<O\|F4>` | 编辑文件;参考文本编辑器文档 | Open |
| `<P>` | 打开日志面板 | Panel |
| `<Q\|F10>` | 退出termscp | Quit |
| `<R\|F7>` | 重命名文件 | Rename |
| `<S\|F2>` | 另存为... | Save |
| `<T>` | 显示所有同步路径 | Track |
| `<U>` | 进入上层目录 | Upper |
| `<V|F3>` | 使用默认方式打开文件 | View |
| `<V\|F3>` | 使用默认方式打开文件 | View |
| `<W>` | 使用指定程序打开文件 | With |
| `<X>` | 运行命令 | eXecute |
| `<Y>` | 是否开启同步浏览 | sYnc |
| `<Z>` | 更改文件权限 | |
| `</>` | 过滤文件(支持正则表达式和通配符匹配) | |
| `<CTRL+A>` | 选中所有文件 | |
| `<ALT+A>` | 取消选择所有文件 | |
| `<CTRL+C>` | 终止文件传输 | |
| `<CTRL+S>` | 获取所选路径的总大小 | Size |
| `<CTRL+T>` | 显示所有同步路径 | Track |
### 处理多个文件
### 操作多个文件 🥷
你可以同时操作多个文件,按`<M>`选定它们,或者按`<CTRL+A>` 全选当前工作目录中的所有文件。一旦一个文件被标记为选择,它将在左边显示一个 "*"。在这种模式下,只有选定的文件会被处理,而当前光标高亮显示的项目会被忽略。在查找结果面板中,也可以对多个文件进行处理。
在处理多个文件时,所有的操作都是可用的,但请注意,有些操作的工作方式略有不同。让我们深入了解一下:
你可以通过以下简单的控制操作多个文件:
- *复制*: 当你复制一个文件时,你会被提示输入完整目标路径名。当处理多个文件时,这个名称指的是所有这些文件将被复制到的目标目录。
- *重命名*: 和复制操作类似, 但是会移动文件到目标路径。
- *保存为*: 和复制操作类似, 但是会写入文件到目标路径。
- `<M>`:标记文件以进行选择
- `<CTRL+A>`:选择当前目录下的所有文件
- `<ALT+A>`:取消选择所有文件
被标记的文件将会以**高亮背景** 显示。
当进行选择操作时,只有被选中的文件会执行操作,而当前高亮显示的项目会被忽略。
即使是在查找结果面板中,也可以操作多个文件。
在操作多个文件时,所有功能都可用,但某些功能会有些许不同。具体如下:
- *复制*:复制时会提示你输入目标名称。操作多个文件时,该名称是目标目录,所有文件将被复制到此目录中。
- *重命名*:与复制相同,但文件将被移动到该目录。
- *另存为*:与复制相同,但文件将被写入该目录。
如果你在某个目录(如 `/home`)中选择了文件,然后切换目录,文件仍会保持被选中状态,并在底部面板的**传输队列** 中显示。
文件被选中时,会将当前*远程*目录与该文件关联;如果文件被传输,它将被传输到与之关联的目录中。
#### 示例
如果我们在本地选择 `/home/a.txt`,此时远程目录是 `/tmp`,然后我们切换到 `/var`,选择 `/var/b.txt`,而此时远程目录为 `/home`,执行传输后的结果为:
- `/home/a.txt` 传输到 `/tmp/a.txt`
- `/var/b.txt` 传输到 `/home/b.txt`
### 同步浏览
@@ -300,7 +412,7 @@ termscp和书签一样只需要保证这些路径是可访问的
- **Local File formatter syntax**:在本地资源管理器中显示每个文件的文件信息的语法。参见[资源管理器格式](#资源管理器格式)
- **Enable notifications?**: 如果设置为 `Yes`,则会显示通知。
- **Notifications: minimum transfer size**: 如果传输大小大于或等于指定值,将显示传输通知。 接受的值格式为 `{UNSIGNED} B/KB/MB/GB/TB/PB`
- **SSH Configuration path**:设置连接到 SCP/SFTP 服务器时使用的 SSH 配置文件。 如果未设置(空),则不会使用任何文件。 你可以指定一个以 `~` 开头的路径来表示主路径(例如 `~/.ssh/config`
- **SSH Configuration path**:设置连接到 SCP/SFTP 服务器时使用的 SSH 配置文件。 如果未设置(空),则不会使用任何文件。 你可以指定一个以 `~` 开头的路径来表示主路径(例如 `~/.ssh/config`. 指定了 termscp 支持的参数 [HERE](https://github.com/veeso/ssh2-config#exposed-attributes).
### SSH Key Storage
@@ -442,9 +554,9 @@ Termscp有很多功能你可能已经注意到了其中之一就是可以
termscp会为每个会话创建一个日志文件该文件在
- `$HOME/.config/termscp/termscp.log` -- Linux/BSD
- `$HOME/Library/Application Support/termscp/termscp.log` -- MacOs
- `FOLDERID_RoamingAppData\termscp\termscp.log` -- Windows
- `$HOME/.cache/termscp/termscp.log` -- Linux/BSD
- `$HOME/Library/Caches/termscp/termscp.log` -- MacOs
- `FOLDERID_LocalAppData\termscp\termscp.log` -- Windows
日志不会被轮换,但只会在每次启动 termcp 后被截断,因此如果您想报告问题并希望附加您的日志文件,请记住在使用前将日志文件保存在安全的地方 再次termscp。
默认情况下,日志记录在 *INFO* 级别报告,因此它不是很详细。
@@ -476,3 +588,26 @@ termscp 将针对这些类型的事件发送桌面通知:
❗ 如果您希望保持关闭通知,您只需进入设置并将 `Enable notifications?` 设置为 `No`😉。
❗ 如果您想更改最小传输大小以显示通知,您可以使用键 `Notifications: minimum transfer size` 更改配置中的值,并将其设置为更适合您的任何值🙂。
## 文件观察者🔭
文件观察器允许您设置与远程主机同步的路径列表。
这意味着每当在同步路径上检测到本地文件系统的更改时,该更改将在 5 秒内自动报告给配置的远程主机路径。
您可以根据需要设置尽可能多的同步路径:
1.将光标放在本地资源管理器上要保持同步的目录/文件上
2. 转到远程主机上要向其报告更改的目录
3. 按`<T>`
4. 对无线电弹出窗口回答 `<YES>`
要取消观看,只需在本地同步路径(或其任何子文件夹)上按 `<T>`
或者,您可以按 `<CTRL + T>` 并按 `<ENTER>` 进入要取消观看的同步路径。
这些更改将报告给远程主机:
- 新文件,文件更改
- 文件移动/重命名
- 文件删除/取消链接
> ❗ 观察者只在一个方向工作(本地>远程)。不可能自动同步远程到本地的更改。

View File

@@ -8,10 +8,12 @@
# -f, -y, --force, --yes
# Skip the confirmation prompt during installation
TERMSCP_VERSION="0.8.0"
TERMSCP_VERSION="0.19.0"
GITHUB_URL="https://github.com/veeso/termscp/releases/download/v${TERMSCP_VERSION}"
DEB_URL="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_amd64.deb"
RPM_URL="${GITHUB_URL}/termscp-${TERMSCP_VERSION}-1.x86_64.rpm"
DEB_URL_AMD64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_amd64.deb"
DEB_URL_AARCH64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_arm64.deb"
PATH="$PATH:/usr/sbin"
set -eu
printf "\n"
@@ -28,6 +30,13 @@ NO_COLOR="$(tput sgr0 2>/dev/null || printf '')"
# Functions
set_termscp_version() {
TERMSCP_VERSION="$1"
GITHUB_URL="https://github.com/veeso/termscp/releases/download/v${TERMSCP_VERSION}"
DEB_URL_AMD64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_amd64.deb"
DEB_URL_AARCH64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}_arm64.deb"
}
info() {
printf '%s\n' "${BOLD}${GREY}>${NO_COLOR} $*"
}
@@ -92,16 +101,20 @@ test_writeable() {
}
elevate_priv() {
if ! has sudo; then
error 'Could not find the command "sudo", needed to install termscp on your system.'
info "If you are on Windows, please run your shell as an administrator, then"
info "rerun this script. Otherwise, please run this script as root, or install"
info "sudo."
exit 1
fi
if ! sudo -v; then
if has sudo; then
if ! sudo -v; then
error "Superuser not granted, aborting installation"
exit 1
fi
sudo="sudo"
elif has doas; then
sudo="doas"
else
error 'Could not find the commands "sudo" or "doas", needed to install termscp on your system.'
info "If you are on Windows, please run your shell as an administrator, then"
info "rerun this script. Otherwise, please run this script as root, or install"
info "sudo or doas."
exit 1
fi
}
@@ -110,9 +123,7 @@ elevate_priv_ex() {
if test_writeable "$check_dir"; then
sudo=""
else
warn "Root permissions are required to install dependecies"
elevate_priv
sudo="sudo"
fi
echo $sudo
}
@@ -153,11 +164,6 @@ detect_arch() {
arch="arm"
fi
if [ "${arch}" != "x86_64" ]; then
error "Unsupported arch ${arch}"
return 1
fi
printf '%s' "${arch}"
}
@@ -182,7 +188,7 @@ confirm() {
# Installers
install_on_bsd() {
try_with_cargo "packages for freeBSD are distribuited no more. Only cargo installations are supported."
try_with_cargo "packages for freeBSD are distribuited no more. Only cargo installations are supported." "freebsd"
}
install_on_arch_linux() {
@@ -199,11 +205,25 @@ install_on_arch_linux() {
$pkg -S termscp
}
install_with_brew() {
info "Installing termscp with brew"
if has termscp; then
info "Upgrading ${GREEN}termscp${NO_COLOR}"
# The OR is used since someone could have installed via cargo previously
brew update && brew upgrade termscp || brew install veeso/termscp/termscp
else
info "Installing ${GREEN}termscp${NO_COLOR}"
brew install veeso/termscp/termscp
fi
}
install_on_linux() {
local msg
local sudo
local archive
if has yay; then
if has pacman; then
install_on_arch_linux pacman
elif has yay; then
install_on_arch_linux yay
elif has pakku; then
install_on_arch_linux pakku
@@ -216,66 +236,40 @@ install_on_linux() {
elif has pikaur; then
install_on_arch_linux pikaur
elif has dpkg; then
if [ "${ARCH}" != "x86_64" ]; then # It's okay on AUR; not on other distros
try_with_cargo "we don't distribute packages for ${ARCH} at the moment"
case "${ARCH}" in
x86_64) DEB_URL="$DEB_URL_AMD64" ;;
aarch64) DEB_URL="$DEB_URL_AARCH64" ;;
*) try_with_cargo "we don't distribute packages for ${ARCH} at the moment" && return $? ;;
esac
info "Detected dpkg on your system"
info "Installing ${GREEN}termscp${NO_COLOR} via Debian package"
archive=$(get_tmpfile "deb")
download "${archive}" "${DEB_URL}"
info "Downloaded debian package to ${archive}"
if test_writeable "/usr/bin"; then
sudo=""
msg="Installing ${GREEN}termscp${NO_COLOR}, please wait…"
else
info "Detected dpkg on your system"
info "Installing ${GREEN}termscp${NO_COLOR} via Debian package"
archive=$(get_tmpfile "deb")
download "${archive}" "${DEB_URL}"
info "Downloaded debian package to ${archive}"
if test_writeable "/usr/bin"; then
sudo=""
msg="Installing ${GREEN}termscp${NO_COLOR}, please wait…"
else
warn "Root permissions are required to install ${GREEN}termscp${NO_COLOR}"
elevate_priv
sudo="sudo"
msg="Installing ${GREEN}termscp${NO_COLOR} as root, please wait…"
fi
info "$msg"
$sudo dpkg -i "${archive}"
rm -f ${archive}
fi
elif has rpm; then
if [ "${ARCH}" != "x86_64" ]; then # It's okay on AUR; not on other distros
try_with_cargo "we don't distribute packages for ${ARCH} at the moment"
else
info "Detected rpm on your system"
info "Installing ${GREEN}termscp${NO_COLOR} via RPM package"
archive=$(get_tmpfile "rpm")
download "${archive}" "${RPM_URL}"
info "Downloaded rpm package to ${archive}"
if test_writeable "/usr/bin"; then
sudo=""
msg="Installing ${GREEN}termscp${NO_COLOR}, please wait…"
else
warn "Root permissions are required to install ${GREEN}termscp${NO_COLOR}"
elevate_priv
sudo="sudo"
msg="Installing ${GREEN}termscp${NO_COLOR} as root, please wait…"
fi
info "$msg"
$sudo rpm -U "${archive}"
rm -f ${archive}
warn "Root permissions are required to install ${GREEN}termscp${NO_COLOR}"
elevate_priv
sudo="sudo"
msg="Installing ${GREEN}termscp${NO_COLOR} as root, please wait…"
fi
info "$msg"
$sudo dpkg -i "${archive}"
rm -f ${archive}
elif has brew; then
install_with_brew
else
try_with_cargo "No suitable installation method found for your Linux distribution; if you're running on Arch linux, please install an AUR package manager (such as yay). Currently only Arch, Debian based and Red Hat based distros are supported"
try_with_cargo "No suitable installation method found for your Linux distribution; if you're running on Arch linux, please install an AUR package manager (such as yay). Currently only Arch, Debian based and Red Hat based distros are supported" "linux"
fi
}
install_on_macos() {
if has brew; then
if has termscp; then
info "Upgrading ${GREEN}termscp${NO_COLOR}"
# The OR is used since someone could have installed via cargo previously
brew update && brew upgrade termscp || brew install veeso/termscp/termscp
else
info "Installing ${GREEN}termscp${NO_COLOR}"
brew install veeso/termscp/termscp
fi
install_with_brew
else
try_with_cargo "brew is missing on your system; please install it from <https://brew.sh/>"
try_with_cargo "brew is missing on your system; please install it from <https://brew.sh/>" "macos"
fi
}
@@ -285,14 +279,14 @@ install_bsd_cargo_deps() {
set -e
confirm "${YELLOW}libssh, gcc${NO_COLOR} are required to install ${GREEN}termscp${NO_COLOR}; would you like to proceed?"
sudo="$(elevate_priv_ex /usr/local/bin)"
$sudo pkg install -y curl wget libssh gcc dbus pkgconf
$sudo pkg install -y curl wget libssh gcc dbus pkgconf libsmbclient
info "Dependencies installed successfully"
}
install_linux_cargo_deps() {
local debian_deps="gcc pkg-config libssl-dev libssh2-1-dev libdbus-1-dev"
local rpm_deps="gcc openssl pkgconfig libdbus-devel openssl-devel"
local arch_deps="gcc openssl pkg-config dbus"
local debian_deps="gcc pkg-config libdbus-1-dev libsmbclient-dev"
local rpm_deps="gcc openssl pkgconfig dbus-devel openssl-devel libsmbclient-devel"
local arch_deps="gcc openssl pkg-config dbus smbclient"
local deps_cmd=""
# Get pkg manager
if has apt; then
@@ -346,11 +340,12 @@ install_cargo() {
try_with_cargo() {
err="$1"
platform="$2"
# Install cargo
install_cargo
if has cargo; then
info "Installing ${GREEN}termscp${NO_COLOR} via Cargo…"
case $PLATFORM in
case $platform in
"freebsd")
install_bsd_cargo_deps
cargo install --locked --no-default-features termscp
@@ -392,6 +387,7 @@ fi
# parse argv variables
while [ "$#" -gt 0 ]; do
echo $1
case "$1" in
-V | --verbose)
@@ -410,7 +406,10 @@ while [ "$#" -gt 0 ]; do
FORCE="${1#*=}"
shift 1
;;
-v=* | --version=*)
set_termscp_version "${1#*=}"
shift 1
;;
*)
error "Unknown option: $1"
exit 1
@@ -452,11 +451,11 @@ case $PLATFORM in
esac
completed "Congratulations! Termscp has successfully been installed on your system!"
info "If you're a new user, you might be interested in reading the user manual <https://veeso.github.io/termscp/#user-manual>"
info "While if you've just updated your termscp version, you can find the changelog at this link <https://veeso.github.io/termscp/#changelog>"
info "If you're a new user, you might be interested in reading the user manual <https://termscp.veeso.dev/user-manual.html>"
info "While if you've just updated your termscp version, you can find the changelog at this link <https://termscp.veeso.dev/#changelog>"
info "Remember that if you encounter any issue, you can report them on Github <https://github.com/veeso/termscp/issues/new>"
info "Feel free to open an issue also if you have an idea which could improve the project"
info "If you want to support the project, please, consider a little donation <https://www.buymeacoffee.com/veeso>"
info "If you want to support the project, please, consider a little donation <https://ko-fi.com/veeso>"
info "I hope you'll enjoy using termscp :D"
exit 0

2
rustfmt.toml Normal file
View File

@@ -0,0 +1,2 @@
group_imports = "StdExternalCrate"
imports_granularity = "Module"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

74
site/changelog.html Normal file
View File

@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en_US" class="dark">
<head>
<title>
termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/Kube/S3/WebDAV/SMB/WebDAV | termscp
</title>
<meta property="og:description"
content="termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/Kube/S3/WebDAV. It is Linux, MacOS, FreeBSD, NetBSD and Windows compatible" />
<meta name="description"
content="termscp is a feature rich terminal file transfer and explorer, with support for SCP/SFTP/FTP/Kube/S3/WebDAV. It is Linux, MacOS, FreeBSD, NetBSD and Windows compatible" />
<meta property="og:title" content="termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/Kube/S3/WebDAV | termscp" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="index, follow" />
<meta property="og:image" content="https://termscp.veeso.dev/assets/images/og_preview.jpg" />
<meta property="og:image:type" content="image/jpg" />
<meta property="og:image:width" content="1280" />
<meta property="og:image:height" content="640" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="termscp" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://termscp.veeso.dev" />
<!-- Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.11.0/devicon.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/fontawesome.min.css"
integrity="sha512-OdEXQYCOldjqUEsuMKsZRj93Ht23QRlhIb8E/X0sbwZhme8eUw6g8q7AdxGJKakcBbv7+/PX0Gc2btf7Ru8cZA=="
crossorigin="anonymous" />
<!-- tailwind -->
<link href="output.css" rel="stylesheet" />
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="96x96" href="assets/images/favicon-96x96.png" />
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicon-16x16.png" />
</head>
<body>
<div id="layout" class="dark:bg-brand dark:text-gray-100">
<!-- Menu -->
<header id="menu"></header>
<main>
<div id="main" class="w-8/12 sm:w-full mx-auto pt-4 pb-8"></div>
</main>
<footer id="footer"></footer>
</div>
<!-- Scripts -->
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- Showdown JS-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js"
integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Local -->
<script src="js/lang.min.js"></script>
<script src="js/core.js"></script>
<script src="js/events.js"></script>
<script src="js/resolvers.js"></script>
<!-- ko-fi -->
<script src="https://storage.ko-fi.com/cdn/scripts/overlay-widget.js"></script>
<script>
kofiWidgetOverlay.draw("veeso", {
type: "floating-chat",
"floating-chat.donateButton.text": "Support me",
"floating-chat.donateButton.background-color": "#31363b",
"floating-chat.donateButton.text-color": "#fff",
});
</script>
</body>
</html>

87
site/css/markdown.css Normal file
View File

@@ -0,0 +1,87 @@
.markdown {
font-family: Arial, Helvetica, sans-serif;
}
.markdown a {
color: dodgerblue;
text-decoration: none;
}
.markdown a:hover {
text-decoration: underline;
}
.markdown p {
font-size: 1.1em;
}
.markdown h1 {
font-size: 2em;
}
.markdown h2 {
font-size: 1.6em;
}
.markdown h3 {
font-size: 1.4em;
}
.markdown h4 {
font-size: 1.2em;
}
.markdown img {
display: none;
}
@media (min-width: 600px) {
.markdown img {
display: block;
width: 60%;
margin-left: 20%;
}
}
.markdown blockquote {
border-left: 0.25em solid #ccc;
font-size: 90%;
padding: 0.1em;
padding-left: 0.5em;
}
.markdown pre code {
background-color: inherit;
font-size: 100%;
}
.markdown code {
background-color: #eee;
border-radius: 6px;
font-size: 85%;
padding: 0.2em 0.4em;
}
:is(.dark) .markdown code {
background-color: #404040;
}
.markdown table {
border-collapse: collapse;
border-spacing: 0;
display: block;
height: fit-content;
max-width: 100%;
overflow: auto;
width: max-content;
}
.markdown table tr {
border-top: 1px solid #c6cbd1;
}
.markdown table td,
.markdown table th {
border: 1px solid #c6cbd1;
padding: 6px 13px;
}

75
site/get-started.html Normal file
View File

@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en_US" class="dark">
<head>
<title>
get started with termscp | termscp
</title>
<meta property="og:description"
content="Install termscp within a couple of minutes with the shell script" />
<meta name="description"
content="Install termscp within a couple of minutes with the shell script" />
<meta property="og:title" content="get started with termscp | termscp" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="index, follow" />
<meta property="og:image" content="https://termscp.veeso.dev/assets/images/og_preview.jpg" />
<meta property="og:image:type" content="image/jpg" />
<meta property="og:image:width" content="1280" />
<meta property="og:image:height" content="640" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="termscp" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://termscp.veeso.dev" />
<!-- Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.11.0/devicon.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/fontawesome.min.css"
integrity="sha512-OdEXQYCOldjqUEsuMKsZRj93Ht23QRlhIb8E/X0sbwZhme8eUw6g8q7AdxGJKakcBbv7+/PX0Gc2btf7Ru8cZA=="
crossorigin="anonymous" />
<!-- tailwind -->
<link href="output.css" rel="stylesheet" />
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="96x96" href="assets/images/favicon-96x96.png" />
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicon-16x16.png" />
</head>
<body>
<div id="layout" class="dark:bg-brand dark:text-gray-100">
<!-- Menu -->
<header id="menu"></header>
<main>
<div id="main" class="w-8/12 sm:w-full mx-auto pt-4 pb-8"></div>
</main>
<footer id="footer"></footer>
</div>
<!-- Scripts -->
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- Showdown JS-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js"
integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Local -->
<script src="js/lang.min.js"></script>
<script src="js/core.js"></script>
<script src="js/events.js"></script>
<script src="js/resolvers.js"></script>
<!-- ko-fi -->
<script src="https://storage.ko-fi.com/cdn/scripts/overlay-widget.js"></script>
<script>
kofiWidgetOverlay.draw("veeso", {
type: "floating-chat",
"floating-chat.donateButton.text": "Support me",
"floating-chat.donateButton.background-color": "#31363b",
"floating-chat.donateButton.text-color": "#fff",
});
</script>
</body>
</html>

View File

@@ -0,0 +1,38 @@
<!DOCTYPE html>
<div class="flex flex-col bg-brand text-gray-200 justify-around items-center gap-12 p-8 sm:pb-24">
<div class="flex flex-row justify-around items-center gap-16 w-3/6 sm:w-full">
<div>
<a href="https://github.com/veeso/termscp" class="text-3xl sm:text-xl no-underline" target="_blank"><i
class="devicon-github-original"></i></a>
</div>
<div>
<a href="https://crates.io/crates/termscp" class="text-3xl sm:text-xl no-underline" target="_blank"><i
class="devicon-rust-plain"></i></a>
</div>
<div>
<a href="https://community.chocolatey.org/packages/termscp" class="text-3xl sm:text-xl no-underline"
target="_blank"><i class="devicon-windows8-plain"></i></a>
</div>
<div>
<a href="https://ko-fi.com/veeso" target="_blank" class="text-3xl sm:text-xl no-underline"><i
class="fa fa-coffee"></i></a>
</div>
</div>
<div class="flex flex-col justify-around gap-1 items-center w-full">
<!-- vat number -->
<p class="text-sm font-thin">
<span>P.IVA IT03104140300 </span>
</p>
<p class="text-xs font-thin">
<span>Via Antonio Marangoni 33, 33100, Udine (UD)</span>
</p>
<!-- Copyright -->
<p class="text-xs font-thin">
<span>Christian Visintin © </span><span resolve-copyright></span>
<span>&nbsp;|&nbsp;</span>
<a class="text-xs font-thin" href="https://veeso.me/en/privacy" target="_blank">Privacy policy</a>
<span>&nbsp;|&nbsp;</span>
<a class="text-xs font-thin" href="https://veeso.me/en/cookie-policy" target="_blank">Cookie policy</a>
</p>
</div>
</div>

View File

@@ -0,0 +1,97 @@
<!DOCTYPE html>
<div
class="flex flex-row fixed bg-gray-100 dark:bg-brand text-brand dark:text-gray-100 border-b border-gray-400 dark:border-gray-800 items-center justify-between w-screen h-auto py-4 px-8">
<!-- Desktop menu-->
<div class="sm:hidden flex flex-row justify-start items-center gap-12 w-full">
<h2 class="lg:text-xl md:text-lg dark:text-gray-100">
<a href="/">
<img class="w-[32px] h-auto m-auto inline-block mr-2 hover:underline" alt="logo"
src="assets/images/termscp.webp" />&nbsp;termscp
</a>
</h2>
<h2 class="lg:text-xl md:text-lg dark:text-gray-100 hover:underline">
<a translate="menu.getStarted" href="/get-started.html"></a>
</h2>
<h2 class="lg:text-xl md:text-lg dark:text-gray-100 hover:underline">
<a translate="menu.updates" href="/updates.html"></a>
</h2>
<h2 class="lg:text-xl md:text-lg dark:text-gray-100 hover:underline">
<a translate="menu.manual" href="/user-manual.html"></a>
</h2>
<h2 class="lg:text-xl md:text-lg dark:text-gray-100 hover:underline">
<a translate="menu.changelog" href="/changelog.html"></a>
</h2>
<!-- End region -->
<div class="flex flex-row self-end justify-end items-center gap-8 flex-1">
<!-- Dark/light theme toggle -->
<button id="theme-toggle" type="button" onclick="toggleTheme()"
class="text-brand dark:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:ring-4 focus:ring-gray-200 dark:focus:ring-gray-700 rounded-lg lg:text-2xl md:text-lg p-2.5">
<svg id="theme-toggle-dark-icon" class="w-5 h-5 hidden" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
</svg>
<svg id="theme-toggle-light-icon" class="w-5 h-5 hidden" fill="currentColor" viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg">
<path
d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"
fill-rule="evenodd" clip-rule="evenodd"></path>
</svg>
</button>
<!-- Socials -->
<div>
<a href="https://github.com/veeso/termscp" class="lg:text-2xl md:text-lg dark:text-gray-100" target="_blank"><i
class="devicon-github-original"></i></a>
</div>
<div>
<a href="https://crates.io/crates/termscp" class="lg:text-2xl md:text-lg dark:text-gray-100" target="_blank"><i
class="devicon-rust-plain"></i></a>
</div>
<div>
<a href="https://www.linkedin.com/in/christian-visintin/" class="lg:text-2xl md:text-lg dark:text-gray-100"
target="_blank"><i class="devicon-linkedin-plain"></i></a>
</div>
<div>
<a href="https://twitter.com/veeso_dev" target="_blank" class="lg:text-2xl md:text-lg dark:text-gray-100"><i
class="devicon-twitter-plain"></i></a>
</div>
</div>
</div>
<!-- Mobile topbar -->
<div class="sm:flex hidden flex-row justify-start items-center gap-8 w-full">
<h2 class="text-2xl dark:text-gray-100">
<a href="/">
<img class="w-[32px] h-auto m-auto inline-block mr-2" alt="logo"
src="assets/images/termscp.webp" />&nbsp;termscp
</a>
</h2>
<div id="menu-icon" class="justify-self-end flex-1 flex justify-end">
<i onclick="onToggleMenu()" class="fa fa-bars text-2xl cursor-pointer"></i>
</div>
</div>
</div>
<!-- Mobile menu -->
<div id="mobile-menu"
class="hidden transition-all fixed top-0 left-0 h-screen bg-brand text-white w-screen flex-col justify-start items-center p-8">
<div class="flex flex-row justify-end items-end w-full">
<div id="menu-icon" class="justify-self-end flex-1 flex justify-end">
<i onclick="onToggleMenu()" class="fa fa-bars text-2xl cursor-pointer"></i>
</div>
</div>
<div class="flex flex-col justify-start items-center w-full gap-4 hover:underline">
<h2 class="text-2xl text-white">
<a translate="menu.intro" href="/"></a>
</h2>
<h2 class="text-2xl text-white hover:underline">
<a translate="menu.getStarted" href="/get-started.html"></a>
</h2>
<h2 class="text-2xl text-white hover:underline">
<a translate="menu.updates" href="/updates.html"></a>
</h2>
<h2 class="text-2xl text-white hover:underline">
<a translate="menu.manual" href="/user-manual.html"></a>
</h2>
<h2 class="text-2xl text-white hover:underline">
<a translate="menu.changelog" href="/changelog.html"></a>
</h2>
</div>
</div>

164
site/html/get-started.html Normal file
View File

@@ -0,0 +1,164 @@
<!DOCTYPE html>
<body>
<section id="start" class="flex flex-col mx-auto items-center justify-center w-full px-12 gap-8 dark:text-gray-100">
<h1 translate="getStarted.title" class="text-3xl font-thin">Get started</h1>
<section class="w-full">
<h2 class="text-2xl font-thin">
<i class="fa fa-rocket"></i>&nbsp;<span translate="getStarted.quickSetup">Quick setup</span>
</h2>
<div class="installation">
<div class="p-4 my-4 text-sm text-blue-800 rounded-lg bg-blue-50">
<p class="text-lg">
<i class="fas fa-info-circle"></i>
<span translate="getStarted.suggested">We strongly suggest this method to install termscp</span>
</p>
</div>
<p translate="getStarted.posixUsers">
If you are a Linux, a FreeBSD or a MacOS user, you can install termscp
via this simple command , which will use a shell script installer:
</p>
<pre><span class="function">curl</span> --proto <span class="string">'=https'</span> --tlsv1.2 -sSLf <span class="string">"https://git.io/JBhDb"</span> | sh</pre>
</div>
</section>
<section class="w-full">
<h2 class="text-2xl font-thin">
<i class="devicon-windows8-plain"></i>&nbsp;<span translate="getStarted.windows.title">Windows users</span>
</h2>
<div class="installation">
<p>
<span translate="getStarted.windows.intro">You can install termscp on Windows via</span>
<a href="https://community.chocolatey.org/packages/termscp" target="_blank">Chocolatey</a>
</p>
<pre><span class="function">choco</span> install <span class="string">termscp</span></pre>
<p>
<span translate="getStarted.windows.moderation">Consider that Chocolatey moderation can take up to a few weeks
since last release, so if the latest version is not available yet,
you can install it downloading the ZIP file from</span>
<a href="https://github.com/veeso/termscp/releases/latest/download/termscp.0.19.0.nupkg"
target="_blank">Github</a>
<span translate="getStarted.windows.then">and then, from the ZIP directory, install it via</span>
</p>
<pre><span class="function">choco</span> install <span class="string">termscp</span> -s .</pre>
</div>
</section>
<section class="w-full">
<h2 class="text-2xl font-thin">
<i class="devicon-linux-plain"></i>&nbsp;<span translate="getStarted.linuxUsers">Linux users</span>
</h2>
<div class="sub-system">
<div class="p-4 my-4 text-sm text-yellow-800 rounded-lg bg-yellow-50">
<p class="text-lg">
<i class="fas fa-exclamation-triangle"></i>
<span translate="getStarted.notConfident">Opt for these methods instead if you don't feel confident using
the shell script</span>
</p>
</div>
<h3>
<i class="devicon-linux-plain"></i>&nbsp;<span translate="getStarted.arch.title">Arch derived users</span>
</h3>
<div class="installation">
<p>
<span translate="getStarted.arch.intro">On Arch Linux based distros, you can install termscp using</span>
<a href="https://wiki.archlinux.org/title/pacman" target="_blank">pacman</a>
<span translate="getStarted.arch.then">then run:</span>
</p>
<pre><span class="function">pacman</span> -S <span class="string">termscp</span></pre>
</div>
<h3>
<i class="devicon-debian-plain"></i>&nbsp;<span translate="getStarted.debian.title">Debian derived
users</span>
</h3>
<div class="installation">
<p translate="getStarted.debian.body">
On Debian based distros, you can install termscp using the Deb
package via:
</p>
<pre><span class="function">wget</span> -O termscp.deb <span class="string">https://github.com/veeso/termscp/releases/latest/download/termscp_0.19.0_amd64.deb</span>
sudo <span class="function">dpkg</span> -i <span class="string">termscp.deb</span></pre>
</div>
<h3>
<i class="devicon-redhat-plain"></i>&nbsp;<span translate="getStarted.redhat.title">Redhat derived
users</span>
</h3>
<h3>
<span>Brew</span>
</h3>
<div class="installation">
<p>
<span translate="getStarted.macos.install">Install termscp via</span>&nbsp;
<a href="https://brew.sh/" target="_blank">Brew</a>
</p>
<pre><span class="function">brew</span> install <span class="string">veeso/termscp/termscp</span></pre>
</div>
</div>
</section>
<section class="w-full">
<h2 class="text-2xl font-thin">
<i class="devicon-apple-plain"></i>&nbsp;<span translate="getStarted.macos.title">MacOS users</span>
</h2>
<div class="installation">
<div class="p-4 my-4 text-sm text-yellow-800 rounded-lg bg-yellow-50">
<p class="text-lg">
<i class="fas fa-exclamation-triangle"></i>
<span translate="getStarted.notConfident">Opt for these methods instead if you don't feel confident using
the shell script</span>
</p>
</div>
<p>
<span translate="getStarted.macos.install">Install termscp via</span>&nbsp;
<a href="https://brew.sh/" target="_blank">Brew</a>
</p>
<pre><span class="function">brew</span> install <span class="string">veeso/termscp/termscp</span></pre>
</div>
</section>
<section class="w-full">
<h2 class="text-2xl font-thin">
<i class="devicon-rust-plain"></i>&nbsp;<span translate="getStarted.cargo.title">Install with Cargo</span>
</h2>
<div class="installation">
<div class="p-4 my-4 text-sm text-yellow-800 rounded-lg bg-yellow-50">
<p class="text-lg">
<i class="fas fa-exclamation-triangle"></i>
<span translate="getStarted.noBinary">Opt for this method instead if binaries for your platform are not
available</span>
</p>
</div>
<p>
<span translate="getStarted.cargo.body">If a package is not available for your system, you can opt to
install termscp via</span>&nbsp;
<a href="https://www.rust-lang.org/tools/install" target="_blank">Cargo</a>.
<span translate="getStarted.cargo.requirements">To install termscp via Cargo, these requirements must be
satisfied:</span>
</p>
<ul class="list-disc px-8">
<li>
Linux:
<ul class="list-disc px-12">
<li>pkg-config</li>
<li>libdbus-1</li>
<li>libsmbclient</li>
</ul>
</li>
<li>
FreeBSD:
<ul class="list-disc px-12">
<li>dbus</li>
<li>pkg-conf</li>
<li>gcc</li>
</ul>
</li>
</ul>
<p translate="getStarted.cargo.install">Then you can install it via</p>
<pre><span class="function">cargo</span> install --locked <span class="string">termscp</span></pre>
<p translate="getStarted.cargo.noKeyring" class="pt-4 pb-2">
Or if you don't want to have support for keyring or you're building on
*BSD:
</p>
<pre><span class="function">cargo</span> install --locked --no-default-features --features smb <span class="string">termscp</span></pre>
<p translate="getStarted.cargo.noSMB" class="pt-4 pb-2"></p>
<pre><span class="function">cargo</span> install --locked --no-default-features --features keyring <span class="string">termscp</span></pre>
</div>
</section>
</section>
</body>

86
site/html/home.html Normal file
View File

@@ -0,0 +1,86 @@
<!DOCTYPE html>
<section id="intro"
class="flex flex-col mx-auto items-center justify-center w-full px-4 dark:bg-brand dark:text-gray-100">
<h1 class="text-3xl text-center font-thin">termscp</h1>
<img class="w-[256px] h-auto m-auto" alt="logo" src="assets/images/termscp.webp" />
<h2 class="text-xl font-thin text-center py-6" translate="intro.caption">
A feature rich terminal UI file transfer and explorer with support for
SCP/SFTP/FTP/Kube/S3/WebDAV/SMB/WebDAV
</h2>
<button class="bg-brand hover:bg-gray-800 text-white font-thin text-xl py-2 px-4 rounded-xl max-w-fit">
<a href="/get-started.html" class="no-underline" translate="intro.getStarted">Get started →</a>
</button>
<div class="p-4 my-4 text-sm text-green-800 rounded-lg bg-green-50">
<p class="text-lg">
<span translate="intro.versionAlert">termscp 0.19.0 is NOW out! Download it from</span>&nbsp;
<a href="/get-started.html" translate="intro.here">here!</a>
</p>
</div>
<div class="grid grid-cols-3 sm:grid-cols-1 gap-8 py-8 w-4/6 sm:w-full">
<div class="feature">
<h3 translate="intro.features.handy.title" class="text-center text-lg">Handy UI</h3>
<p translate="intro.features.handy.body" class="text-center">
Explore and operate on the remote and on the local machine file system
with a handy UI.
</p>
</div>
<div class="feature">
<h3 translate="intro.features.crossPlatform.title" class="text-center text-lg">Cross platform</h3>
<p translate="intro.features.crossPlatform.body" class="text-center">
Runs on Windows, MacOS, Linux and BSD
</p>
</div>
<div class="feature">
<h3 translate="intro.features.customizable.title" class="text-center text-lg">Customizable</h3>
<p translate="intro.features.customizable.body" class="text-center">
Customize the file explorer, the text editor to use and default
options
</p>
</div>
<div class="feature">
<h3 translate="intro.features.bookmarks.title" class="text-center text-lg">Bookmarks</h3>
<p translate="intro.features.bookmarks.body" class="text-center">
Connect to your favourite hosts through built-in bookmarks and recent
connections support
</p>
</div>
<div class="feature">
<h3 translate="intro.features.security.title" class="text-center text-lg">Security first</h3>
<p translate="intro.features.security.body" class="text-center">
Save your password into your operating system key vault
</p>
</div>
<div class="feature">
<h3 translate="intro.features.performance.title" class="text-center text-lg">Eye on performance</h3>
<p translate="intro.features.performance.body" class="text-center">
termscp has been developed keeping an eye on performance to prevent
cpu usage
</p>
</div>
</div>
<div class="w-4/6 sm:w-5/6">
<video autoplay muted loop>
<source src="assets/videos/explorer.mp4" type="video/mp4" resolve-video-fallback="assets/images/explorer.gif" />
</video>
</div>
<hr class="h-px my-8 bg-gray-800 border-0" />
<div class="flex flex-row sm:flex-col justify-around gap-12">
<div class="hook">
<h3 class="text-center text-gray-500 dark:text-gray-100 font-light text-xl">
<a href="/get-started.html" class="no-underline hover:underline" translate="intro.footer.getStarted">Get
started</a>
</h3>
</div>
<div class="hook">
<h3 class="text-center text-gray-500 dark:text-gray-100 font-light text-xl">
<a href="/user-manual.html" class="no-underline hover:underline" translate="intro.footer.manual">User manual</a>
</h3>
</div>
<div class="hook">
<h3 class="text-center text-gray-500 dark:text-gray-100 font-light text-xl">
<a href="/updates.html" class="no-underline hover:underline" translate="intro.footer.updates">Install
updates</a>
</h3>
</div>
</div>
</section>

100
site/html/updates.html Normal file
View File

@@ -0,0 +1,100 @@
<head>
<link rel="stylesheet" href="css/updates.css" />
</head>
<body>
<section id="updates" class="flex flex-col mx-auto items-center justify-center w-full px-12 gap-8 dark:text-gray-100">
<h1 translate="updates.title" class="text-3xl font-thin">Keeping termscp up to date</h1>
<!-- Reasons -->
<section>
<h2 class="text-2xl font-thin">
<i class="fa fa-question-circle"></i>&nbsp;<span translate="updates.reasons.title">Why should you install
updates</span>
</h2>
<div class="wall-of-text">
<p translate="updates.reasons.wallOfText" class="text-gray-700 dark:text-gray-300">
Termscp is an application that is still in its early stage of
development, the first version has been released in december in 2020
and practically there's only one
<a href="https://termscp.veeso.dev/" target="_blank">guy</a> working on
it and there's still a lot of work to do in order to improve it and
make it fast and reliable. Along to this, you should also consider
that since it's an application which works with network protocols and
is intended to manipulate secrets and credentials there may always be
a security issue. I can't guarantee there's no security issues in the
versions I've released in these months, and if there are they might
not be even my fault, but they might be contained in the libraries
termscp relies on. Because of this, it's always VERY important to keep
termscp up to date. To prove how much I care about it, just consider
that I've implemented something that many other open source
applications won't do: the update check. Whenever you start termscp
(unless if deactivated in configuration) termscp will always check if
there's a new version available and will notify you immediately. In
addition to security concerns, each major update will bring many
awesome features 🦄 you can't miss and the application is getting more
reliable and stable after each update 😄
</p>
<p class="italic text-xl text-gray-700 dark:text-gray-300">
<span>TL;DR</span>
<span translate="updates.reasons.tldr"></span>
</p>
</div>
</section>
<!-- Gui method -->
<section>
<h2 class="text-2xl font-thin"><i class="fa fa-desktop"></i>&nbsp;<span translate="updates.gui.title">GUI
method</span></h2>
<div class="installation">
<p translate="updates.gui.body" class="text-gray-700 dark:text-gray-300">
The GUI method just consists in starting termscp with no options, you
then should be in front of the authentication form. If there's an
update available a message like "termscp x.y.z is OUT! Update and read
release notes with CTRL+R". All you have to do at this point to update
termscp, is:
</p>
<ol class="list-decimal px-8 text-gray-700 dark:text-gray-300">
<li translate="updates.gui.steps.st">press CTRL+R. The release notes should now be displayed.</li>
<li translate="updates.gui.steps.nd">Select "YES" in the "Install update?" radio input</li>
<li translate="updates.gui.steps.rd">Press "ENTER"</li>
</ol>
<p translate="updates.gui.then" class="text-gray-700 dark:text-gray-300">
If everything worked correctly a green message "termscp x.y.z has been
installed!" will be displayed. Just restart termscp and enjoy the
update 😄
</p>
<div class="p-4 my-4 text-sm text-yellow-800 rounded-lg bg-yellow-50">
<p>
<i class="fas fa-exclamation-triangle"></i>
<span translate="updates.gui.pex">
If you have previously installed termscp via Deb package, you
may need to use the CLI method running termscp with sudo
</span>
</p>
</div>
</div>
</section>
<!-- CLI method -->
<section>
<h2 class="text-2xl font-thin"><i class="fa fa-glasses"></i>&nbsp;<span translate="updates.cli.title">CLI
method</span></h2>
<div class="installation">
<p translate="updates.cli.body" class="text-gray-700 dark:text-gray-300">
If you prefer, you can install a new update just using the dedicated
CLI option:
</p>
<pre><span class="function">termscp</span> --update</pre>
<div class="p-4 my-4 text-sm text-yellow-800 rounded-lg bg-yellow-50">
<p>
<i class="fas fa-exclamation-triangle"></i>
<span translate="updates.cli.pex">Run with sudo if necessary (Debian/FreeBSD/RedHat users)</span>
</p>
</div>
<p translate="updates.cli.then" class="text-gray-700 dark:text-gray-300">
Once started, you will be prompted whether to install or not the
update. Confirm the installation and ta-dah, the new version of
termscp should now be available on your machine
</p>
</div>
</section>
</section>
</body>

76
site/index.html Normal file
View File

@@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="en_US" class="dark">
<head>
<title>
termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/Kube/S3/WebDAV/SMB/WebDAV | termscp
</title>
<meta property="og:description"
content="a WinSCP alternative for Linux and MacOS with support for SCP/SFTP/FTP/Kube/S3/WebDAV/SMB/WebDAV. Command line file transfer with user interface compatible with all the operating systems." />
<meta name="description"
content="a WinSCP alternative for Linux and MacOS with support for SCP/SFTP/FTP/Kube/S3/WebDAV/SMB/WebDAV. Command line file transfer with user interface compatible with all the operating systems." />
<meta property="og:title"
content="termscp is a terminal file transfer and explorer for SCP/SFTP/FTP/Kube/S3/WebDAV/SMB/WebDAV | termscp" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="index, follow" />
<meta property="og:image" content="https://termscp.veeso.dev/assets/images/og_preview.jpg" />
<meta property="og:image:type" content="image/jpg" />
<meta property="og:image:width" content="1280" />
<meta property="og:image:height" content="640" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="termscp" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://termscp.veeso.dev" />
<!-- Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.11.0/devicon.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/fontawesome.min.css"
integrity="sha512-OdEXQYCOldjqUEsuMKsZRj93Ht23QRlhIb8E/X0sbwZhme8eUw6g8q7AdxGJKakcBbv7+/PX0Gc2btf7Ru8cZA=="
crossorigin="anonymous" />
<!-- tailwind -->
<link href="output.css" rel="stylesheet" />
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="96x96" href="assets/images/favicon-96x96.png" />
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicon-16x16.png" />
</head>
<body>
<div id="layout" class="dark:bg-brand dark:text-gray-100">
<!-- Menu -->
<header id="menu"></header>
<main>
<div id="main" class="w-8/12 sm:w-full mx-auto pt-4 pb-8"></div>
</main>
<footer id="footer"></footer>
</div>
<!-- Scripts -->
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- Showdown JS-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js"
integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Local -->
<script src="js/lang.min.js"></script>
<script src="js/core.js"></script>
<script src="js/events.js"></script>
<script src="js/resolvers.js"></script>
<!-- ko-fi -->
<script src="https://storage.ko-fi.com/cdn/scripts/overlay-widget.js"></script>
<script>
kofiWidgetOverlay.draw("veeso", {
type: "floating-chat",
"floating-chat.donateButton.text": "Support me",
"floating-chat.donateButton.background-color": "#31363b",
"floating-chat.donateButton.text-color": "#fff",
});
</script>
</body>
</html>

132
site/input.css Normal file
View File

@@ -0,0 +1,132 @@
@import "css/markdown.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
@font-face {
font-family: "Sora";
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sora/v11/xMQ9uFFYT72X5wkB_18qmnndmSdSnx2BAfO5mnuyOo1l_iMwWa-xsaQ.woff2)
format("woff2");
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Sora";
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sora/v11/xMQ9uFFYT72X5wkB_18qmnndmSdSnx2BAfO5mnuyOo1l_iMwV6-x.woff2)
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
font-family: "Sora";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sora/v11/xMQ9uFFYT72X5wkB_18qmnndmSdSnx2BAfO5mnuyOo1l_iMwWa-xsaQ.woff2)
format("woff2");
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Sora";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sora/v11/xMQ9uFFYT72X5wkB_18qmnndmSdSnx2BAfO5mnuyOo1l_iMwV6-x.woff2)
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
U+FEFF, U+FFFD;
}
html {
scroll-behavior: smooth;
}
body {
font-family: "Sora", sans-serif;
margin: 0;
min-width: 100vw;
overflow-x: hidden;
padding: 0;
}
main {
padding-top: 5rem;
}
p {
font-weight: 300;
}
input {
font-family: "Sora", sans-serif;
font-size: 1em;
}
textarea {
font-family: "Sora", sans-serif;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-top: 0;
margin-bottom: 0.5rem;
}
button {
box-sizing: border-box;
cursor: pointer;
}
button,
input {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
a {
text-decoration: none;
}
a:hover {
text-decoration: none;
}
pre {
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
padding: 16px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
color: #d0d0d0;
background-color: #222629;
border-radius: 3px;
word-wrap: normal;
border-radius: 0.5em;
}
pre .function {
color: #f08d49;
}
pre .string {
color: #7ec699;
}

131
site/js/core.js Normal file
View File

@@ -0,0 +1,131 @@
/**
* @description return navigator language. If language is not supported default will be returned
* @returns {string}
*/
function getNavigatorLanguage() {
let lang = navigator.language;
// Complete lang
if (languageSupported(lang)) {
return lang;
}
// Reduced lang
lang = lang.split(/[-_]/)[0] || "en";
if (!languageSupported(lang)) {
return "en";
}
return lang;
}
/**
* @description check whether provided language is supported by the website
* @param {string} lang
* @returns {boolean}
*/
function languageSupported(lang) {
return ["en", "zh-CN", "it", "fr", "es"].includes(lang);
}
/**
* @description update website language
* @param {string} lang
*/
function setSiteLanguage(lang) {
setLanguage(lang);
}
const converter = new showdown.Converter({ tables: true });
/**
* @description load page associated to hash
* @param {string} hash
*/
function loadPage(path) {
switch (path) {
case "/":
case "/index.html":
loadHtml("home.html");
break;
case "/get-started.html":
loadHtml("get-started.html");
break;
case "/user-manual.html":
loadUserManual();
break;
case "/updates.html":
loadHtml("updates.html");
break;
case "/changelog.html":
loadMarkdown(
"https://raw.githubusercontent.com/veeso/termscp/main/CHANGELOG.md"
);
break;
}
}
function loadHtml(page) {
const url = "html/" + page;
$("#main").load(url, function () {
onPageLoaded();
});
}
function loadMenu() {
$("#menu").load("html/components/menu.html", function () {
onPageLoaded();
});
}
function loadFooter() {
$("#footer").load("html/components/footer.html", function () {
onPageLoaded();
});
}
function loadMarkdown(page) {
getMarkdown(page, function (md) {
const div = jQuery("<div/>", {
id: page,
class: "container markdown",
});
div.html(converter.makeHtml(md));
$("#main").empty();
$("#main").append(div);
onPageLoaded();
});
}
/**
* @description get markdown and pass result to onLoaded
* @param {string} url
* @param {function} onLoaded
*/
function getMarkdown(url, onLoaded) {
$.ajax({
url,
type: "GET",
dataType: "text",
success: onLoaded,
});
}
function loadUserManual() {
// Load language
const lang = getNavigatorLanguage();
if (lang === "en") {
loadMarkdown(
`https://raw.githubusercontent.com/veeso/termscp/main/docs/man.md`
);
} else {
loadMarkdown(
`https://raw.githubusercontent.com/veeso/termscp/main/docs/${lang}/man.md`
);
}
}
// startup
$(function () {
loadPage(window.location.pathname);
loadMenu();
loadFooter();
});

81
site/js/events.js Normal file
View File

@@ -0,0 +1,81 @@
function onPageLoaded() {
reloadTranslations();
setThemeToggle();
setTheme(getTheme());
}
function onToggleMenu() {
const mobileMenu = $("#mobile-menu");
let wasVisible = false;
// if not visible set flex and slide in, otherwise slide out
if (!mobileMenu.is(":visible")) {
mobileMenu.css("display", "flex");
mobileMenu.addClass("animate__animated animate__slideInLeft");
} else {
mobileMenu.addClass("animate__animated animate__slideOutLeft");
wasVisible = true;
}
// on animation end remove animation, if visible set hidden
mobileMenu.on("animationend", () => {
mobileMenu.removeClass(
"animate__animated animate__slideOutLeft animate__slideInLeft"
);
if (wasVisible) {
mobileMenu.css("display", "none");
}
mobileMenu.off("animationend");
});
}
function getTheme() {
const theme = localStorage.getItem("theme");
if (!theme) {
return window.matchMedia("(prefers-color-scheme: dark)").matches
? "theme-dark"
: "theme-light";
}
return theme;
}
function setThemeToggle() {
if (getTheme() === "theme-dark") {
$("#theme-toggle-dark-icon").css("display", "block");
$("#theme-toggle-light-icon").css("display", "none");
} else {
$("#theme-toggle-dark-icon").css("display", "none");
$("#theme-toggle-light-icon").css("display", "block");
}
}
// function to set a given theme/color-scheme
function setTheme(themeName) {
localStorage.setItem("theme", themeName);
if (themeName === "theme-dark") {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
setThemeToggle();
}
// function to toggle between light and dark theme
function toggleTheme() {
console.log("theme", getTheme());
if (getTheme() === "theme-dark") {
setTheme("theme-light");
} else {
setTheme("theme-dark");
}
}
// Startup
$(function () {
// Init language
setSiteLanguage(getNavigatorLanguage());
// init theme
setTheme(getTheme());
});

1
site/js/lang.min.js vendored Normal file
View File

@@ -0,0 +1 @@
var currentLanguage=null;var languagePath="lang/";var currentLanguageDict=null;function setLanguage(lang){currentLanguage=lang;const jsonFile=languagePath+currentLanguage+".json";$.getJSON(jsonFile,function(langData){currentLanguageDict=flatDict(langData);reloadTranslations()})}function reloadTranslations(){$("[translate]").each(function(){const translationAttr=$(this).attr("translate");$(this).text(getInstantTranslation(translationAttr))})}function getInstantTranslation(key){if(currentLanguageDict!==null&&key in currentLanguageDict){return currentLanguageDict[key]}else{return"{{ "+key+" }}"}}function flatDict(dict){const iterNode=(flatten,path,node)=>{for(const key of Object.keys(node)){const child=node[key];const childKey=path?path+"."+key:key;if(typeof child==="object"){flatten=iterNode(flatten,childKey,child)}else{flatten[childKey]=child}}return flatten};return iterNode({},null,dict)}

32
site/js/resolvers.js Normal file
View File

@@ -0,0 +1,32 @@
/**
* @description resolve copyright year
*/
function resolveCopyright() {
const year = new Date().getFullYear();
$("[resolve-copyright]").each(function () {
$(this).text(year);
});
}
/**
* @description resolve video fallback source in case fails. Uses an image instead
*/
function resolveVideoFallback() {
$("[resolve-video-fallback]").each(function () {
const fallback = $(this).attr("resolve-video-fallback");
// Add listener
$(this).on("error", function () {
const image = document.createElement("img");
image.src = fallback;
image.classList = ["preview"];
$(this).parent().replaceWith(image);
});
});
}
// init
$(function () {
resolveCopyright();
resolveVideoFallback();
});

115
site/lang/en.json Normal file
View File

@@ -0,0 +1,115 @@
{
"menu": {
"desc": "A feature rich terminal UI file transfer",
"intro": "Intro",
"getStarted": "Get started",
"updates": "Install updates",
"manual": "User manual",
"changelog": "Release history",
"author": "About the author",
"support": "Support me"
},
"intro": {
"caption": "A feature rich terminal UI file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/WebDAV",
"getStarted": "Get started →",
"versionAlert": "termscp 0.19.0 is NOW out! Download it from",
"here": "here",
"features": {
"handy": {
"title": "Handy UI",
"body": "Explore and operate on the remote and on the local machine file system with a handy UI."
},
"crossPlatform": {
"title": "Cross platform",
"body": "Runs on Windows, MacOS, Linux and FreeBSD"
},
"customizable": {
"title": "Customizable",
"body": "Customize the file explorer, the UI and many other parameters..."
},
"bookmarks": {
"title": "Bookmarks",
"body": "Connect to your favourite hosts through built-in bookmarks and recent connections"
},
"security": {
"title": "Security first",
"body": "Save your passwords into your operating system key vault"
},
"performance": {
"title": "Eye on performance",
"body": "termscp has been developed keeping an eye on performance to prevent high cpu usage"
}
},
"footer": {
"getStarted": "Get started",
"manual": "User manual",
"updates": "Install updates"
}
},
"getStarted": {
"title": "Get started",
"quickSetup": "Quick setup",
"suggested": "We strongly suggest this method to install termscp",
"posixUsers": "If you are a Linux, a FreeBSD or a MacOS user, you can install termscp via this simple command , which will use a shell script installer:",
"windows": {
"title": "Windows users",
"intro": "You can install termscp on Windows via",
"moderation": "Consider that Chocolatey moderation can take up to a few weeks since last release, so if the latest version is not available yet, you can install it downloading the ZIP file from",
"then": "and then, from the ZIP directory, install it via"
},
"linuxUsers": "Linux users",
"notConfident": "Opt for these methods instead if you don't feel confident using the shell script",
"noBinary": "Opt for this method instead if binaries for your platform are not available or you want to select features",
"arch": {
"title": "Arch derived users",
"intro": "On Arch Linux based distros, you can install termscp using",
"then": "then run"
},
"debian": {
"title": "Debian derived users",
"body": "On Debian based distros, you can install termscp using the Deb package via:"
},
"redhat": {
"title": "Redhat derived users",
"body": "On RedHat based distros, you can install termscp using the RPM package via:"
},
"macos": {
"title": "MacOS users",
"install": "Install termscp via"
},
"cargo": {
"title": "Install with Cargo",
"body": "If a package is not available for your system, you can opt to install termscp via",
"requirements": "To install termscp via Cargo, these requirements must be satisfied",
"install": "Then you can install termscp via",
"noKeyring": "Or if you don't want to have support for keyring or you're building on *BSD:",
"noSMB": "Or if you want to disable SMB:"
}
},
"updates": {
"title": "Keeping termscp up to date",
"disclaimer": " Updating termscp with this method is only available for 0.7.x versions or higher. If you have an older version, you have to install updates using the",
"reasons": {
"title": "Why you should install updates",
"wallOfText": "Termscp is an application that is still in its early stage of development, the first version has been released in december in 2020 and practically there's only one guy working on it and there's still a lot of work to do in order to improve it and make it fast and reliable. Along to this, you should also consider that since it's an application which works with network protocols and is intended to manipulate secrets and credentials there may always be a security issue. I can't guarantee there's no security issues in the versions I've released in these months, and if there are they might not be even my fault, but they might be contained in the libraries termscp relies on. Because of this, it's always VERY important to keep termscp up to date. To prove how much I care about it, just consider that I've implemented something that many other open source applications won't do: the update check. Whenever you start termscp (unless if deactivated in configuration) termscp will always check if there's a new version available and will notify you immediately. In addition to security concerns, each major update will bring many awesome features 🦄 you can't miss and the application is getting more reliable and stable after each update 😄",
"tldr": "Possible security issues; new awesome features; performance and stability; Bugfixes"
},
"gui": {
"title": "GUI method",
"body": "The GUI method just consists in starting termscp with no options, you then should be in front of the authentication form. If there's an update available a message like \"termscp x.y.z is OUT! Update and read release notes with CTRL+R\". All you have to do at this point to update termscp, is:",
"steps": {
"st": "press CTRL+R. The release notes should now be displayed",
"nd": "Select \"YES\" in the \"Install update?\" radio input",
"rd": "Press \"Enter\""
},
"then": "If everything worked correctly a green message \"termscp x.y.z has been installed!\" will be displayed. Just restart termscp and enjoy the update 😄",
"pex": " If you have previously installed termscp via Deb/RPM package, you may need to use the CLI method running termscp with sudo"
},
"cli": {
"title": "CLI method",
"body": "If you prefer, you can install a new update just using the dedicated CLI option:",
"pex": "Run with sudo if necessary (installed with RPM/DEB)",
"then": "Once started, you will be prompted whether to install or not the update. Confirm the installation and ta-dah, the new version of termscp should now be available on your machine"
}
}
}

115
site/lang/es.json Normal file
View File

@@ -0,0 +1,115 @@
{
"menu": {
"desc": "Una transferencia de archivos de terminal rica en funciones",
"intro": "Sobre termscp",
"getStarted": "Para iniciar",
"updates": "Actualizaciones",
"manual": "Manual de usuario",
"changelog": "Historial de versiones",
"author": "Sobre el autor",
"support": "Apoyame"
},
"intro": {
"caption": "Un explorador y transferencia de archivos de terminal rico en funciones, con apoyo para SCP/SFTP/FTP/Kube/S3/WebDAV",
"getStarted": "Para iniciar →",
"versionAlert": "termscp 0.19.0 ya está disponible! Descárgalo desde",
"here": "aquì",
"features": {
"handy": {
"title": "Interfaz de usuario práctica",
"body": "Explore y opere en el sistema de archivos de la máquina local y remota con una interfaz de usuario práctica."
},
"crossPlatform": {
"title": "Multiplataforma",
"body": "Funciona en Windows, MacOS, Linux y FreeBSD"
},
"customizable": {
"title": "Personalizable",
"body": "Personalice el explorador de archivos, la interfaz de usuario y muchos otros parámetros ..."
},
"bookmarks": {
"title": "Marcadores",
"body": "Conéctese a sus hosts favoritos a través de marcadores integrados y conexiones recientes"
},
"security": {
"title": "Seguridad primero",
"body": "Guarde sus contraseñas en la bóveda de claves de su sistema operativo"
},
"performance": {
"title": "Ojo en el rendimiento",
"body": "termscp se ha desarrollado teniendo en cuenta el rendimiento para evitar un uso elevado de la CPU"
}
},
"footer": {
"getStarted": "Para iniciar",
"manual": "Manual de usuario",
"updates": "Actualizaciones"
}
},
"getStarted": {
"title": "Para iniciar",
"quickSetup": "Configuración rápida",
"suggested": "Recomendamos encarecidamente este método para instalar termscp",
"posixUsers": "Si es un usuario de Linux, FreeBSD o MacOS, puede instalar termscp a través de este sencillo comando, que utilizará un instalador de scripts de shell:",
"windows": {
"title": "Usuarios Windows",
"intro": "Puede instalar termscp en Windows a través de",
"moderation": "Tenga en cuenta que la moderación de Chocolatey puede tardar hasta algunas semanas desde la última versión, por lo que si la última versión aún no está disponible, puede instalarla descargando el archivo ZIP de",
"then": "y luego, desde el directorio ZIP, instálelo a través de"
},
"linuxUsers": "Usuarios Linux",
"notConfident": "En su lugar, opte por estos métodos si no se siente seguro al usar el script de shell",
"noBinary": "Opte por este método en su lugar si los binarios para su plataforma no están disponibles",
"arch": {
"title": "Usuarios derivadas Arch",
"intro": "En las distribuciones basadas en Arch Linux, puede instalar termscp usando un administrador de paquetes AUR como",
"then": "then run"
},
"debian": {
"title": "Usuarios derivadas Debian",
"body": "En las distribuciones basadas en Debian, puede instalar termscp usando el paquete Deb a través de:"
},
"redhat": {
"title": "Usuarios derivadas RedHat",
"body": "En las distribuciones basadas en RedHat, puede instalar termscp usando el paquete RPM a través de:"
},
"macos": {
"title": "Usuarios MacOS",
"install": "Instalar termscp a través de"
},
"cargo": {
"title": "Instalar con Cargo",
"body": "Si un paquete no está disponible para su sistema, puede optar por instalar termscp a través de",
"requirements": "Para instalar termscp a través de Cargo, se deben cumplir estos requisitos",
"install": "Entonces puedes instalar termscp a través de",
"noKeyring": "O si no desea tener soporte para llavero o está construyendo sobre *BSD:",
"noSMB": "O si no desea tener soporte para SMB:"
}
},
"updates": {
"title": "Mantener termscp actualizado",
"disclaimer": " La actualización de termscp con este método solo está disponible para las versiones 0.7.xo superiores. Si tiene una versión anterior, debe instalar actualizaciones utilizando el",
"reasons": {
"title": "Why you should install updates",
"wallOfText": "Termscp es una aplicación que aún se encuentra en su etapa inicial de desarrollo, la primera versión se lanzó en diciembre de 2020 y prácticamente solo hay un chico trabajando en ella y aún hay mucho trabajo por hacer para mejorarla y hacerla. rápido y confiable. Junto con esto, también debe considerar que, dado que es una aplicación que funciona con protocolos de red y está destinada a manipular secretos y credenciales, siempre puede haber un problema de seguridad. No puedo garantizar que no haya problemas de seguridad en las versiones que lancé en estos meses, y si los hay, puede que ni siquiera sea mi culpa, pero pueden estar contenidos en las bibliotecas en las que se basa termscp. Debido a esto, siempre es MUY importante mantener el termcp actualizado. Para demostrar cuánto me importa, solo considere que he implementado algo que muchas otras aplicaciones de código abierto no harán: la verificación de actualizaciones. Siempre que inicie termscp (a menos que esté desactivado en la configuración), termscp siempre comprobará si hay una nueva versión disponible y le notificará inmediatamente. Además de las preocupaciones de seguridad, cada actualización importante traerá muchas características increíbles 🦄 no puede perderse y la aplicación se vuelve más confiable y estable después de cada actualización 😄",
"tldr": "Posibles problemas de seguridad; nuevas funciones asombrosas; rendimiento y estabilidad; Corrección de errores"
},
"gui": {
"title": "Método GUI",
"body": "El método GUI solo consiste en iniciar termscp sin opciones, luego debe estar frente al formulario de autenticación. Si hay una actualización disponible, aparecerá un mensaje como \"termscp x.y.z is OUT! Install update and read release notes with <CTRL + R>\". Todo lo que tiene que hacer en este punto para actualizar termscp es:",
"steps": {
"st": "presione CTRL + R. Las notas de la versión deberían mostrarse ahora",
"nd": "Seleccione \"Yes\" en la entrada de radio \"Install update? \"",
"rd": "presione \"Enter\""
},
"then": "If everything worked correctly a green message \"termscp x.y.z has been installed!\" will be displayed. Just restart termscp and enjoy the update 😄",
"pex": " Si ha instalado previamente termscp a través del paquete Deb / RPM, es posible que deba utilizar el método CLI ejecutando termscp con sudo"
},
"cli": {
"title": "Método CLI",
"body": "Si lo prefiere, puede instalar una nueva actualización simplemente usando la opción CLI dedicada:",
"pex": "Ejecute con sudo si es necesario (instalado con RPM / DEB)",
"then": "Una vez iniciado, se le preguntará si desea instalar o no la actualización. Confirme la instalación y ta-dah, la nueva versión de termscp ahora debería estar disponible en su máquina"
}
}
}

115
site/lang/fr.json Normal file
View File

@@ -0,0 +1,115 @@
{
"menu": {
"desc": "Un file transfer de terminal riche en fonctionnalités",
"intro": "Intro",
"getStarted": "Pour commencer",
"updates": "Mise à jours",
"manual": "Manuel utilisateur",
"changelog": "Changelog",
"author": "A propos de l'auteur",
"support": "Me soutenir"
},
"intro": {
"caption": "Un file transfer et navigateur de terminal riche en fonctionnalités avec support pour SCP/SFTP/FTP/Kube/S3/WebDAV",
"getStarted": "Pour commencer →",
"versionAlert": "termscp 0.19.0 est maintenant sorti! Télécharge-le depuis",
"here": "ici",
"features": {
"handy": {
"title": "Interface utilisateur pratique",
"body": "Explorez et utilisez le système de fichiers distant et local avec une interface utilisateur pratique."
},
"crossPlatform": {
"title": "Multi-plateforme",
"body": "Fonctionne sur Windows, MacOS, Linux et FreeBSD"
},
"customizable": {
"title": "Personnalisable",
"body": "Personnalisez l'explorateur de fichiers, l'interface utilisateur et bien d'autres paramètres..."
},
"bookmarks": {
"title": "Signets",
"body": "Connectez-vous à vos hôtes préférés via des signets intégrés et des connexions récentes"
},
"security": {
"title": "Sécurité avant tout",
"body": "Enregistrez vos mots de passe dans le coffre-fort de votre système"
},
"performance": {
"title": "Regard sur les performances",
"body": "termscp a été développé en gardant un œil sur les performances pour éviter une utilisation élevée du processeur"
}
},
"footer": {
"getStarted": "Pour commencer",
"manual": "Manuel d'utilisateur",
"updates": "Mise à jour"
}
},
"getStarted": {
"title": "Pour commencer",
"quickSetup": "Installation rapide",
"suggested": "Nous suggérons fortement cette méthode pour installer termscp",
"posixUsers": "Si vous êtes un utilisateur Linux, FreeBSD ou MacOS, vous pouvez installer termscp via cette simple commande , qui utilisera un installateur de script shell :",
"windows": {
"title": "Utilisateurs Windows",
"intro": "Vous pouvez installer termscp sur Windows via",
"moderation": "Considérez que la modération Chocolatey peut prendre jusqu'à quelques semaines depuis la dernière version, donc si la dernière version n'est pas encore disponible, vous pouvez l'installer en téléchargeant le fichier ZIP depuis",
"then": "puis, depuis le répertoire ZIP, installez-le via"
},
"linuxUsers": "Utilisateurs Linux",
"notConfident": "Optez plutôt pour ces méthodes si vous ne vous sentez pas à l'aise avec le script shell",
"noBinary": "Optez plutôt pour cette méthode si les binaires pour votre plate-forme ne sont pas disponibles",
"arch": {
"title": "Utilisateurs dérivés Arch",
"intro": "Sur les distributions basées sur Arch Linux, vous pouvez installer termscp à l'aide d'un gestionnaire de packages AUR tel que",
"then": "puis, installez-le via"
},
"debian": {
"title": "Utilisateurs dérivés Debian",
"body": "Sur les distributions basées sur Debian, vous pouvez installer termscp en utilisant le paquet Deb via :"
},
"redhat": {
"title": "Utilisateurs dérivés RedHat",
"body": "Sur les distributions basées sur RedHat, vous pouvez installer termscp à l'aide du package RPM via :"
},
"macos": {
"title": "Utilisateurs MacOS",
"install": "Installez termscp via"
},
"cargo": {
"title": "Installer avec Cargo",
"body": "Si un package n'est pas disponible pour votre système, vous pouvez choisir d'installer Termscp via",
"requirements": "Pour installer termscp via Cargo, ces conditions doivent être remplies",
"install": "Ensuite, vous pouvez installer termscp via",
"noKeyring": "Ou si vous ne voulez pas avoir de support pour le trousseau de clés ou si vous construisez sur *BSD :",
"noSMB": "Ou si vous ne voulez pas avoir de support pour SMB:"
}
},
"updates": {
"title": "Tenir à jour termscp",
"disclaimer": " La mise à jour de termscp avec cette méthode n'est disponible que pour les versions 0.7.x ou supérieures. Si vous avez une ancienne version, vous devez installer les mises à jour en utilisant le",
"reasons": {
"title": "Pourquoi devriez-vous installer les mises à jour",
"wallOfText": "termscp est une application qui est encore à ses débuts de développement, la première version est sortie en décembre 2020 et pratiquement il n'y a qu'un seul gars qui travaille dessus et il y a encore beaucoup de travail à faire pour l'améliorer et le faire rapide et fiable. Parallèlement à cela, vous devez également considérer que, puisqu'il s'agit d'une application qui fonctionne avec des protocoles réseau et est destinée à manipuler des secrets et des informations d'identification, il peut toujours y avoir un problème de sécurité. Je ne peux pas garantir qu'il n'y ait pas de problèmes de sécurité dans les versions que j'ai publiées au cours de ces mois, et s'il y en a, ce n'est peut-être même pas de ma faute, mais ils pourraient être contenus dans les bibliothèques sur lesquelles s'appuie Termscp. Pour cette raison, il est toujours TRÈS important de maintenir termscp à jour. Pour prouver à quel point j'y tiens, considérez simplement que j'ai implémenté quelque chose que de nombreuses autres applications open source ne feront pas : la vérification des mises à jour. Chaque fois que vous démarrez termscp (sauf s'il est désactivé dans la configuration), termscp vérifiera toujours si une nouvelle version est disponible et vous en informera immédiatement. En plus des problèmes de sécurité, chaque mise à jour majeure apportera de nombreuses fonctionnalités impressionnantes 🦄 vous ne pouvez pas manquer et l'application devient plus fiable et stable après chaque mise à jour 😄",
"tldr": "Problèmes de sécurité possibles ; de nouvelles fonctionnalités impressionnantes ; performances et stabilité; Corrections de bugs"
},
"gui": {
"title": "Méthode GUI",
"body": "La méthode GUI consiste simplement à démarrer termscp sans options, vous devriez alors être devant le formulaire d'authentification. S'il y a une mise à jour disponible, un message comme \"termscp x.y.z is now OUT ! Install updated and read the release notes with CTRL+R\". Tout ce que vous avez à faire à ce stade pour mettre à jour termscp, c'est :",
"steps": {
"st": "appuyez sur CTRL+R. Les notes de version devraient maintenant être affichées",
"nd": "Sélectionnez \"YES\" dans l'entrée radio \"Install update?\"",
"rd": "appuyez \"Enter\""
},
"then": "Si tout a fonctionné correctement, un message vert \"termscp x.y.z has been installed!\" s'affichera. Redémarrez simplement Termscp et profitez de la mise à jour",
"pex": " Si vous avez déjà installé termscp via le package Deb/RPM, vous devrez peut-être utiliser la méthode CLI exécutant termscp avec sudo"
},
"cli": {
"title": "Méthode CLI",
"body": "Si vous préférez, vous pouvez installer le mise à jour avec l'option CLI dédié :",
"pex": "Exécuter avec sudo si nécessaire (installé avec RPM/DEB)",
"then": "Une fois démarré, vous serez invité à installer ou non la mise à jour. Confirmez l'installation et ta-dah, la nouvelle version de termscp devrait maintenant être disponible sur votre machine"
}
}
}

115
site/lang/it.json Normal file
View File

@@ -0,0 +1,115 @@
{
"menu": {
"desc": "Un file transfer ricco di funzionalità",
"intro": "Intro",
"getStarted": "Per iniziare",
"updates": "Aggiornamenti",
"manual": "Manuale",
"changelog": "Rilasci",
"author": "Sull'autore",
"support": "Supportami"
},
"intro": {
"caption": "Un file transfer ed explorer ricco di funzionalità con supporto per SFTP/SCP/FTP/S3",
"getStarted": "Installa termscp →",
"versionAlert": "termscp 0.19.0 è ORA disponbile! Scaricalo da",
"here": "qui",
"features": {
"handy": {
"title": "UI ergonomica",
"body": "Naviga e lavora sulla macchina remote e locale attraverso una UI di facile utilizzo"
},
"crossPlatform": {
"title": "Multi piattaforma",
"body": "Gira su Windows, MacOS, Linux e FreeBSD"
},
"customizable": {
"title": "Personalizzabile",
"body": "Personalizza l'explorer, l'interfaccia e molto altro..."
},
"bookmarks": {
"title": "Preferiti",
"body": "Connetitit ai tuoi host preferiti e accedi in velocemente alle tue ultime sessioni"
},
"security": {
"title": "Sicurezza in prima classe",
"body": "Salva le tue password nel vault del tuo sistema operativo"
},
"performance": {
"title": "Focus sulle performance",
"body": "termscp è stato sviluppato tenendo conto delle performance, per garantirti il minor consumo di risore possibile"
}
},
"footer": {
"getStarted": "Per iniziare",
"manual": "Manuale utente",
"updates": "Aggiornamenti"
}
},
"getStarted": {
"title": "Installazione",
"quickSetup": "Installazione veloce",
"suggested": "Suggeriamo questo metodo per installare termscp",
"posixUsers": "Se sei un utente Linux, MacOS o *BSD puoi installare termscp con questo semplice comando, che utilizzerà un semplice script per installare l'applicazione;",
"windows": {
"title": "Utenti Windows",
"intro": "Puoi installare termscp su Windows tramite",
"moderation": "Attenzione che i moderatori di chocolatey potrebbero metterci qualche settimana ad approvare l'ultima versione, quindi se l'ultima versione non fosse ancora disponibile, puoi installarla tramite il file ZIP da",
"then": "e poi, dalla directory dello ZIP, lo installi con"
},
"linuxUsers": "Utenti Linux",
"notConfident": "Opta per questi metodi nel caso non ti fidi dello script install.sh",
"noBinary": "Opta per questo metodo nel caso non fosse disponibile un binario per la tua piattaforma",
"arch": {
"title": "Utenti derivate Arch",
"intro": "Sulle distro derivate da Arch puoi installare termscp tramite un package manager AUR come",
"then": "e poi lanciare"
},
"debian": {
"title": "Utenti derivate Debian",
"body": "Sulle distro derivate Debian puoi installare termscp tramite il pacchetto Deb, con:"
},
"redhat": {
"title": "Utenti derivate RedHat",
"body": "Sulle distro derivate RedHat puoi installare termscp tramite il pacchetto RPM, con:"
},
"macos": {
"title": "Utenti MacOS",
"install": "Installa termscp con"
},
"cargo": {
"title": "Installa con Cargo",
"body": "Se un pacchetto non è disponibile per il tuo sistema, puoi installare termscp con cargo con",
"requirements": "Per installare con Cargo, questi requisiti di sistema devono essere soddisfatti",
"install": "Infine puoi installare termscp con",
"noKeyring": "O se non hai il supporto a DBUS o sei un utente *BSD:",
"noSMB": "O se vuoi disabilitare il supporto per SMB:"
}
},
"updates": {
"title": "Mantenere termscp all'ultima versione",
"disclaimer": "L'aggiornamento di termscp con il metodo descritto è disponibile solo per le versioni suaccessive o uguali alla 0.7.x. Nel caso tu abbia una versione precedente, puoi aggiornare termscp tramite il",
"reasons": {
"title": "Perché dovresti aggiornare termscp",
"wallOfText": "Termscp è un'applicazione che è ancora all'inizio del suo ciclo di vita, la prima versione è infatti risalente a dicembre 2020 e praticamente c'è solo una persona che ci lavora. C'è ancora molto da fare prima di renderlo veloce, sicuro al 100% ed affidabile. Oltre a questo devi considerare che lavorando con protocolli di rete che utilizzano autenticazione ci potrebbero sempre essere delle falle di sicurezza nelle librerie su cui ci appoggiamo e non ho modo ad oggi di garantire che non ce ne siano. Per questo motivo è sempre importante mantenere termscp all'ultima versione e leggere i changelog del progetto. Tanto per capirci su quanto ci tenga a mantenere le versioni all'ultima versione, questo è uno dei pochi progetti CLI ad avere la possibilità di installarlo direttamente dall'applicazione Comunque oltre a possibili falle di sicurezza e bug, ad ogni aggiornamento introdurrò nuove fantastiche funzionalità 🦄 da non perdere 😄",
"tldr": "Possibili problemi di sicurezza; nuove features; performance e stabilità; bug fix"
},
"gui": {
"title": "Metodo da interfaccia grafica",
"body": "Il metodo da interfaccia grafica richiede di lanciare termscp senza argomenti, a questo punto nella pagina dell'autenticazione dovresti essere notificato di una nuova versione disponibile, tramite un messaggio tipo \"termscp x.y.z is OUT! Update and read release notes with CTRL+R\". A questo punto ti basterà:",
"steps": {
"st": "Premere CTRL+R. Le note di rilascio saranno visualizzate in un popup",
"nd": "Seleziona \"YES\" nel dialogo radio \"Install update?\"",
"rd": "Premi \"Invio\""
},
"then": "Se tutto è andato a buon fine un messaggio con scritto \"termscp x.y.z has been installed!\" sarà visualizzato. A questo punto riavvia termscp e goditi le novità 😄",
"pex": " Se in precedenza hai installato termscp con pacchetto Deb/RPM, dovresti aver bisogno di lanciare termscp da utente sudo. Nel caso ti consiglio il metodo CLI."
},
"cli": {
"title": "Metodo da linea di comando",
"body": "Se preferisci o devi installare con sudo, puoi installare termscp lanciandolo con l'opzione da linea di comando:",
"pex": "Lancialo con sudo se necessario (tipo se l'hai installato con pacchetto RPM/DEB)",
"then": "Una volta lanciato, se c'è un aggiornamento disponibile ti chiederà se procedere. Conferma e a questo punto dovrebbe installarlo. Se tutto è andato a buon fine, riavviando termscp dovrebbe essere l'ultima versione."
}
}
}

115
site/lang/zh-CN.json Normal file
View File

@@ -0,0 +1,115 @@
{
"menu": {
"desc": "功能丰富的终端文件传输",
"intro": "介绍",
"getStarted": "开始",
"updates": "安装更新",
"manual": "用户手册",
"changelog": "发布历史",
"author": "关于作者",
"support": "支持我"
},
"intro": {
"caption": "功能丰富的终端 UI 文件传输和浏览器,支持 SCP/SFTP/FTP/Kube/S3/WebDAV",
"getStarted": "开始 →",
"versionAlert": "termscp 0.19.0 现已发布! 从下载",
"here": "这里",
"features": {
"handy": {
"title": "方便的用户界面",
"body": "使用方便的 UI 在远程和本地机器文件系统上探索和操作。"
},
"crossPlatform": {
"title": "跨平台",
"body": "在 Windows、MacOS、Linux 和 FreeBSD 上运行"
},
"customizable": {
"title": "可定制",
"body": "自定义文件浏览器、UI 和许多其他参数..."
},
"bookmarks": {
"title": "书签",
"body": "通过内置书签和最近的连接连接到您最喜欢的主机"
},
"security": {
"title": "安全第一",
"body": "将您的密码保存到您的操作系统密钥保管库中"
},
"performance": {
"title": "关注性能",
"body": "已经开发了 termscp 关注性能以防止高 CPU 使用率"
}
},
"footer": {
"getStarted": "开始",
"manual": "用户手册",
"updates": "安装更新"
}
},
"getStarted": {
"title": "开始",
"quickSetup": "快速设置",
"suggested": "我们强烈建议使用这种方法来安装termscp",
"posixUsers": "如果您是 Linux、FreeBSD 或 MacOS 用户,您可以通过这个简单的命令安装 termscp它将使用 shell 脚本安装程序:",
"windows": {
"title": "Windows 用户",
"intro": "安装",
"moderation": "考虑到 Chocolatey 审核自上次发布以来可能需要长达数周的时间,因此如果最新版本尚不可用,您可以从以下位置下载 ZIP 文件进行安装",
"then": "然后,从 ZIP 目录,安装它"
},
"linuxUsers": "Linux 用户",
"notConfident": "如果您对使用 shell 脚本没有信心,请选择这些方法",
"noBinary": "如果您的平台的二进制文件不可用,请改用此方法",
"arch": {
"title": "Arch派生用户",
"intro": "在基于 Arch Linux 的发行版上,您可以使用 AUR 包管理器安装 termscp例如",
"then": "然后运行"
},
"debian": {
"title": "Debian派生用户",
"body": "在基于 Debian 的发行版上,您可以通过以下方式使用 Deb 包安装 termscp"
},
"redhat": {
"title": "Redhat派生用户",
"body": "在基于 RedHat 的发行版上,您可以通过以下方式使用 RPM 包安装 termscp"
},
"macos": {
"title": "MacOS 用户",
"install": "通过以下方式安装termscp"
},
"cargo": {
"title": "使用“Cargo”安装",
"body": "如果您的系统没有可用的软件包,您可以选择通过以下方式安装 termscp",
"requirements": "要通过 Cargo 安装termscp必须满足这些要求",
"install": "然后你可以通过安装termscp",
"noKeyring": "或者,如果您不想支持密钥环,或者您正在构建 *BSD",
"noSMB": "或者如果你想禁用 SMB :"
}
},
"updates": {
"title": "使termscp保持最新",
"disclaimer": " 使用此方法更新 termscp 仅适用于 0.7.x 版本或更高版本。 如果您有旧版本,则必须使用",
"reasons": {
"title": "为什么要安装更新",
"wallOfText": "termscp 是一个仍处于早期开发阶段的应用程序,第一个版本已于 2020 年 12 月发布,实际上只有一个人在开发它,为了改进它并使其成功,还有很多工作要做快速可靠。除此之外,您还应该考虑到,由于它是一个使用网络协议的应用程序,旨在操纵机密和凭据,因此可能始终存在安全问题。我不能保证我这几个月发布的版本没有安全问题,如果有,它们甚至可能不是我的错,但它们可能包含在 termscp 依赖的库中。因此保持termscp 最新总是非常重要的。为了证明我有多关心它请考虑一下我已经实现了许多其他开源应用程序不会做的事情更新检查。每当您启动termscp除非在配置中停用termscp 将始终检查是否有新版本可用并立即通知您。除了安全问题,每次重大更新都会带来许多很棒的功能🦄你不能错过,每次更新后应用程序都变得更加可靠和稳定😄",
"tldr": "可能的安全问题; 新的很棒的功能; 性能和稳定性; Bug修复"
},
"gui": {
"title": "图形用户界面方式",
"body": "GUI 方法只包括启动没有选项的 termscp然后您应该位于身份验证表单的前面。 如果有可用更新,则会显示类似\"termscp x.y.z is OUT! Update and read release notes with CTRL+R\"之类的消息。 此时更新termscp所需要做的就是",
"steps": {
"st": "按 CTRL+R。 现在应该显示发行说明",
"nd": "在 \"Install update?\" 单选输入中选择 \"YES\"",
"rd": "按 \"Enter\""
},
"then": "termscp x.y.z has been installed”。 只需重新启动termscp并享受更新😄",
"pex": " 如果您之前已经通过 Deb/RPM 包安装了 termscp您可能需要使用 CLI 方法通过 sudo 运行 termscp"
},
"cli": {
"title": "命令行方式",
"body": "如果您愿意,可以仅使用专用 CLI 选项安装新更新:",
"pex": "如有必要,使用 sudo 运行(使用 RPM/DEB 安装)",
"then": "启动后,系统将提示您是否安装更新。 确认安装和 ta-dah新版本的termscp 现在应该可以在你的机器上使用了"
}
}
}

3
site/output.css Normal file

File diff suppressed because one or more lines are too long

2
site/robots.txt Normal file
View File

@@ -0,0 +1,2 @@
User-Agent: *
Allow: /

29
site/sitemap.xml Normal file
View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<url>
<loc>https://termscp.veeso.dev/</loc>
<lastmod>2023-07-05</lastmod>
<priority>1.00</priority>
</url>
<url>
<loc>https://termscp.veeso.dev/get-started.html</loc>
<lastmod>2023-07-05</lastmod>
<priority>0.95</priority>
</url>
<url>
<loc>https://termscp.veeso.dev/updates.html</loc>
<lastmod>2023-07-05</lastmod>
<priority>0.80</priority>
</url>
<url>
<loc>https://termscp.veeso.dev/user-manual.html</loc>
<lastmod>2023-07-05</lastmod>
<priority>0.90</priority>
</url>
<url>
<loc>https://termscp.veeso.dev/changelog.html</loc>
<lastmod>2023-07-05</lastmod>
<priority>0.50</priority>
</url>
</urlset>

75
site/updates.html Normal file
View File

@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en_US" class="dark">
<head>
<title>
Install termscp updates | termscp
</title>
<meta property="og:description"
content="How to update termscp. Keep termscp up to date with the built-in command." />
<meta name="description"
content="How to update termscp. Keep termscp up to date with the built-in command." />
<meta property="og:title" content="Install termscp updates | termscp" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="index, follow" />
<meta property="og:image" content="https://termscp.veeso.dev/assets/images/og_preview.jpg" />
<meta property="og:image:type" content="image/jpg" />
<meta property="og:image:width" content="1280" />
<meta property="og:image:height" content="640" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="termscp" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://termscp.veeso.dev" />
<!-- Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.11.0/devicon.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/fontawesome.min.css"
integrity="sha512-OdEXQYCOldjqUEsuMKsZRj93Ht23QRlhIb8E/X0sbwZhme8eUw6g8q7AdxGJKakcBbv7+/PX0Gc2btf7Ru8cZA=="
crossorigin="anonymous" />
<!-- tailwind -->
<link href="output.css" rel="stylesheet" />
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="96x96" href="assets/images/favicon-96x96.png" />
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicon-16x16.png" />
</head>
<body>
<div id="layout" class="dark:bg-brand dark:text-gray-100">
<!-- Menu -->
<header id="menu"></header>
<main>
<div id="main" class="w-8/12 sm:w-full mx-auto pt-4 pb-8"></div>
</main>
<footer id="footer"></footer>
</div>
<!-- Scripts -->
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- Showdown JS-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js"
integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Local -->
<script src="js/lang.min.js"></script>
<script src="js/core.js"></script>
<script src="js/events.js"></script>
<script src="js/resolvers.js"></script>
<!-- ko-fi -->
<script src="https://storage.ko-fi.com/cdn/scripts/overlay-widget.js"></script>
<script>
kofiWidgetOverlay.draw("veeso", {
type: "floating-chat",
"floating-chat.donateButton.text": "Support me",
"floating-chat.donateButton.background-color": "#31363b",
"floating-chat.donateButton.text-color": "#fff",
});
</script>
</body>
</html>

75
site/user-manual.html Normal file
View File

@@ -0,0 +1,75 @@
<!DOCTYPE html>
<html lang="en_US" class="dark">
<head>
<title>
termscp user manual | termscp
</title>
<meta property="og:description"
content="How to use termscp. User manual for termscp. How to setup ssh keys in termscp? How to set color themes in termscp?" />
<meta name="description"
content="How to use termscp. User manual for termscp. How to setup ssh keys in termscp? How to set color themes in termscp?" />
<meta property="og:title" content="termscp user manual | termscp" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="index, follow" />
<meta property="og:image" content="https://termscp.veeso.dev/assets/images/og_preview.jpg" />
<meta property="og:image:type" content="image/jpg" />
<meta property="og:image:width" content="1280" />
<meta property="og:image:height" content="640" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="termscp" />
<meta property="og:locale" content="en_US" />
<meta property="og:url" content="https://termscp.veeso.dev" />
<!-- Icons -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.11.0/devicon.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/fontawesome.min.css"
integrity="sha512-OdEXQYCOldjqUEsuMKsZRj93Ht23QRlhIb8E/X0sbwZhme8eUw6g8q7AdxGJKakcBbv7+/PX0Gc2btf7Ru8cZA=="
crossorigin="anonymous" />
<!-- tailwind -->
<link href="output.css" rel="stylesheet" />
<!-- Favicons -->
<link rel="icon" type="image/png" sizes="96x96" href="assets/images/favicon-96x96.png" />
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicon-16x16.png" />
</head>
<body>
<div id="layout" class="dark:bg-brand dark:text-gray-100">
<!-- Menu -->
<header id="menu"></header>
<main>
<div id="main" class="w-8/12 sm:w-full mx-auto pt-4 pb-8"></div>
</main>
<footer id="footer"></footer>
</div>
<!-- Scripts -->
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- Showdown JS-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/1.9.1/showdown.min.js"
integrity="sha512-L03kznCrNOfVxOUovR6ESfCz9Gfny7gihUX/huVbQB9zjODtYpxaVtIaAkpetoiyV2eqWbvxMH9fiSv5enX7bw=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Local -->
<script src="js/lang.min.js"></script>
<script src="js/core.js"></script>
<script src="js/events.js"></script>
<script src="js/resolvers.js"></script>
<!-- ko-fi -->
<script src="https://storage.ko-fi.com/cdn/scripts/overlay-widget.js"></script>
<script>
kofiWidgetOverlay.draw("veeso", {
type: "floating-chat",
"floating-chat.donateButton.text": "Support me",
"floating-chat.donateButton.background-color": "#31363b",
"floating-chat.donateButton.text-color": "#fff",
});
</script>
</body>
</html>

View File

@@ -2,47 +2,29 @@
//!
//! `activity_manager` is the module which provides run methods and handling for activities
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// Deps
use crate::filetransfer::FileTransferParams;
use crate::host::{HostError, Localhost};
use crate::system::config_client::ConfigClient;
use crate::system::environment;
use crate::system::theme_provider::ThemeProvider;
use crate::ui::activities::{
auth::AuthActivity, filetransfer::FileTransferActivity, setup::SetupActivity, Activity,
ExitReason,
};
use crate::ui::context::Context;
// Namespaces
use std::path::{Path, PathBuf};
use std::env;
use std::path::PathBuf;
use std::time::Duration;
/// ### NextActivity
///
use remotefs_ssh::SshKeyStorage as SshKeyStorageTrait;
use crate::cli::{Remote, RemoteArgs};
use crate::filetransfer::{
FileTransferParams, FileTransferProtocol, HostBridgeParams, ProtocolParams,
};
use crate::host::HostError;
use crate::system::bookmarks_client::BookmarksClient;
use crate::system::config_client::ConfigClient;
use crate::system::environment;
use crate::system::sshkey_storage::SshKeyStorage;
use crate::system::theme_provider::ThemeProvider;
use crate::ui::activities::auth::AuthActivity;
use crate::ui::activities::filetransfer::FileTransferActivity;
use crate::ui::activities::setup::SetupActivity;
use crate::ui::activities::{Activity, ExitReason};
use crate::ui::context::Context;
use crate::utils::{fmt, tty};
/// NextActivity identifies the next identity to run once the current has ended
pub enum NextActivity {
Authentication,
@@ -50,21 +32,28 @@ pub enum NextActivity {
SetupActivity,
}
/// ### ActivityManager
///
pub enum Host {
HostBridge,
Remote,
}
pub enum HostParams {
HostBridge(HostBridgeParams),
Remote(FileTransferParams),
}
/// The activity manager takes care of running activities and handling them until the application has ended
pub struct ActivityManager {
context: Option<Context>,
ticks: Duration,
local_dir: PathBuf,
}
impl ActivityManager {
/// Initializes a new Activity Manager
pub fn new(local_dir: &Path, ticks: Duration) -> Result<ActivityManager, HostError> {
pub fn new(ticks: Duration, keyring: bool) -> Result<ActivityManager, HostError> {
// Prepare Context
// Initialize configuration client
let (config_client, error): (ConfigClient, Option<String>) =
let (config_client, error_config): (ConfigClient, Option<String>) =
match Self::init_config_client() {
Ok(cli) => (cli, None),
Err(err) => {
@@ -72,19 +61,211 @@ impl ActivityManager {
(ConfigClient::degraded(), Some(err))
}
};
let (bookmarks_client, error_bookmark) = match Self::init_bookmarks_client(keyring) {
Ok(cli) => (cli, None),
Err(err) => (None, Some(err)),
};
let error = error_config.or(error_bookmark);
let theme_provider: ThemeProvider = Self::init_theme_provider();
let ctx: Context = Context::new(config_client, theme_provider, error);
let ctx: Context = Context::new(bookmarks_client, config_client, theme_provider, error);
Ok(ActivityManager {
context: Some(ctx),
local_dir: local_dir.to_path_buf(),
ticks,
})
}
/// Configure remote args
pub fn configure_remote_args(&mut self, remote_args: RemoteArgs) -> Result<(), String> {
// Set for host bridge
match remote_args.host_bridge {
Remote::Bookmark(params) => self.resolve_bookmark_name(
Host::HostBridge,
&params.name,
params.password.as_deref(),
),
Remote::Host(host_params) => self.set_host_params(
HostParams::HostBridge(HostBridgeParams::Remote(
host_params.file_transfer_params.protocol,
host_params.file_transfer_params.params,
)),
host_params.password.as_deref(),
),
Remote::None => {
// local dir is remote_args.local_dir if set, otherwise current dir
let local_dir = remote_args
.local_dir
.unwrap_or_else(|| env::current_dir().unwrap());
debug!("host bridge is None, setting local dir to {:?}", local_dir,);
self.set_host_params(
HostParams::HostBridge(HostBridgeParams::Localhost(local_dir)),
None,
)
}
}?;
// set remote
match remote_args.remote {
Remote::Bookmark(params) => {
self.resolve_bookmark_name(Host::Remote, &params.name, params.password.as_deref())
}
Remote::Host(host_params) => self.set_host_params(
HostParams::Remote(host_params.file_transfer_params),
host_params.password.as_deref(),
),
Remote::None => Ok(()),
}
}
/// Set file transfer params
pub fn set_filetransfer_params(&mut self, params: FileTransferParams) {
pub fn set_host_params(
&mut self,
host: HostParams,
password: Option<&str>,
) -> Result<(), String> {
let (remote_local_path, remote_remote_path) = match &host {
HostParams::Remote(params) => (params.local_path.clone(), params.remote_path.clone()),
_ => (None, None),
};
let mut remote_params = match &host {
HostParams::HostBridge(HostBridgeParams::Remote(protocol, protocol_params)) => {
Some((*protocol, protocol_params.clone()))
}
HostParams::HostBridge(HostBridgeParams::Localhost(_)) => None,
HostParams::Remote(ft_params) => Some((ft_params.protocol, ft_params.params.clone())),
};
// Put params into the context
self.context.as_mut().unwrap().set_ftparams(params);
if let Some((protocol, params)) = remote_params.as_mut() {
self.resolve_password_for_protocol_params(*protocol, params, password)?;
}
match host {
HostParams::HostBridge(HostBridgeParams::Localhost(path)) => {
self.context
.as_mut()
.unwrap()
.set_host_bridge_params(HostBridgeParams::Localhost(path));
}
HostParams::HostBridge(HostBridgeParams::Remote(_, _)) => {
let (protocol, params) = remote_params.unwrap();
self.context
.as_mut()
.unwrap()
.set_host_bridge_params(HostBridgeParams::Remote(protocol, params));
}
HostParams::Remote(_) => {
let (protocol, params) = remote_params.unwrap();
let params = FileTransferParams {
local_path: remote_local_path,
remote_path: remote_remote_path,
protocol,
params,
};
self.context.as_mut().unwrap().set_remote_params(params);
}
}
Ok(())
}
fn resolve_password_for_protocol_params(
&mut self,
protocol: FileTransferProtocol,
params: &mut ProtocolParams,
password: Option<&str>,
) -> Result<(), String> {
// Set password if provided
if params.password_missing() {
if let Some(password) = password {
params.set_default_secret(password.to_string());
} else if matches!(
protocol,
FileTransferProtocol::Scp | FileTransferProtocol::Sftp,
) && params.generic_params().is_some()
{
// * if protocol is SCP or SFTP check whether a SSH key is registered for this remote, in case not ask password
let storage = SshKeyStorage::from(self.context.as_ref().unwrap().config());
let generic_params = params.generic_params().unwrap();
if storage
.resolve(
&generic_params.address,
&generic_params
.username
.clone()
.unwrap_or(whoami::username()),
)
.is_none()
{
debug!(
"storage could not find any suitable key for {}... prompting for password",
generic_params.address
);
self.prompt_password(params)?;
} else {
debug!(
"a key is already set for {}; password is not required",
generic_params.address
);
}
} else {
self.prompt_password(params)?;
}
}
Ok(())
}
/// Prompt user for password to set into params.
fn prompt_password(&mut self, params: &mut ProtocolParams) -> Result<(), String> {
let ctx = self.context.as_mut().unwrap();
let prompt = format!("Password for {}: ", params.host_name());
match tty::read_secret_from_tty(ctx.terminal(), prompt) {
Err(err) => Err(format!("Could not read password: {err}")),
Ok(Some(secret)) => {
debug!(
"Read password from tty: {}",
fmt::shadow_password(secret.as_str())
);
params.set_default_secret(secret);
Ok(())
}
Ok(None) => Ok(()),
}
}
/// Resolve provided bookmark name and set it as file transfer params.
/// Returns error if bookmark is not found
pub fn resolve_bookmark_name(
&mut self,
host: Host,
bookmark_name: &str,
password: Option<&str>,
) -> Result<(), String> {
if let Some(bookmarks_client) = self.context.as_mut().unwrap().bookmarks_client_mut() {
let params = match bookmarks_client.get_bookmark(bookmark_name) {
None => {
return Err(format!(
r#"Could not resolve bookmark name: "{bookmark_name}" no such bookmark"#
));
}
Some(params) => params,
};
let params = match host {
Host::Remote => HostParams::Remote(params),
Host::HostBridge => {
HostParams::HostBridge(HostBridgeParams::Remote(params.protocol, params.params))
}
};
self.set_host_params(params, password)
} else {
Err(String::from(
"Could not resolve bookmark name: bookmarks client not initialized",
))
}
}
///
@@ -173,26 +354,36 @@ impl ActivityManager {
return None;
}
};
let host_bridge_params = match ctx.host_bridge_params() {
Some(params) => params.clone(),
None => {
error!("Failed to start FileTransferActivity: host bridge params is None");
return None;
}
};
// If ft params is None, return None
let ft_params: &FileTransferParams = match ctx.ft_params() {
let remote_params: &FileTransferParams = match ctx.remote_params() {
Some(ft_params) => ft_params,
None => {
error!("Failed to start FileTransferActivity: file transfer params is None");
return None;
}
};
// Prepare activity
let host: Localhost = match Localhost::new(self.local_dir.clone()) {
Ok(host) => host,
Err(err) => {
// Set error in context
error!("Failed to initialize localhost: {}", err);
ctx.set_error(format!("Could not initialize localhost: {}", err));
return None;
}
};
let mut activity: FileTransferActivity =
FileTransferActivity::new(host, ft_params, self.ticks);
// try to setup activity
let mut activity =
match FileTransferActivity::new(host_bridge_params, remote_params, self.ticks) {
Ok(activity) => activity,
Err(err) => {
error!("Failed to start FileTransferActivity: {}", err);
ctx.set_error(err);
self.context = Some(ctx);
// Return to authentication
return Some(NextActivity::Authentication);
}
};
// Prepare result
let result: Option<NextActivity>;
// Create activity
@@ -256,6 +447,10 @@ impl ActivityManager {
// -- misc
fn init_bookmarks_client(keyring: bool) -> Result<Option<BookmarksClient>, String> {
crate::support::bookmarks_client(keyring)
}
/// Initialize configuration client
fn init_config_client() -> Result<ConfigClient, String> {
// Get config dir
@@ -268,7 +463,7 @@ impl ActivityManager {
environment::get_config_paths(config_dir.as_path());
match ConfigClient::new(config_path.as_path(), ssh_dir.as_path()) {
Ok(cli) => Ok(cli),
Err(err) => Err(format!("Could not read configuration: {}", err)),
Err(err) => Err(format!("Could not read configuration: {err}")),
}
}
None => Err(String::from(
@@ -277,8 +472,7 @@ impl ActivityManager {
}
}
Err(err) => Err(format!(
"Could not initialize configuration directory: {}",
err
"Could not initialize configuration directory: {err}"
)),
}
}
@@ -293,19 +487,28 @@ impl ActivityManager {
match ThemeProvider::new(theme_path.as_path()) {
Ok(provider) => provider,
Err(err) => {
error!("Could not initialize theme provider with file '{}': {}; using theme provider in degraded mode", theme_path.display(), err);
error!(
"Could not initialize theme provider with file '{}': {}; using theme provider in degraded mode",
theme_path.display(),
err
);
ThemeProvider::degraded()
}
}
}
None => {
error!("This system doesn't provide a configuration directory; using theme provider in degraded mode");
error!(
"This system doesn't provide a configuration directory; using theme provider in degraded mode"
);
ThemeProvider::degraded()
}
}
}
Err(err) => {
error!("Could not initialize configuration directory: {}; using theme provider in degraded mode", err);
error!(
"Could not initialize configuration directory: {}; using theme provider in degraded mode",
err
);
ThemeProvider::degraded()
}
}

161
src/cli.rs Normal file
View File

@@ -0,0 +1,161 @@
//! ## CLI opts
//!
//! defines the types for main.rs types
mod remote;
use std::path::PathBuf;
use std::time::Duration;
use argh::FromArgs;
pub use remote::{Remote, RemoteArgs};
use crate::activity_manager::NextActivity;
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<PathBuf>),
ImportTheme(PathBuf),
InstallUpdate,
Version,
}
#[derive(Default, FromArgs)]
#[argh(description = "
where positional can be:
- [address_a] [address_b] [local-wrkdir]
OR
- -b [bookmark-name_1] -b [bookmark-name_2] [local-wrkdir]
and any combination of the above
Address syntax can be:
- `protocol://user@address:port:wrkdir` for protocols such as Sftp, Scp, Ftp
- `s3://bucket-name@region:profile:/wrkdir` for Aws S3 protocol
- `\\\\<server>[:port]\\<share>[\\path]` for SMB (on Windows)
- `smb://[user@]<server>[:port]</share>[/path]` for SMB (on other systems)
Please, report issues to <https://github.com/veeso/termscp>
Please, consider supporting the author <https://ko-fi.com/veeso>")]
pub struct Args {
#[argh(subcommand)]
pub nested: Option<ArgsSubcommands>,
/// resolve address argument as a bookmark name
#[argh(option, short = 'b')]
pub bookmark: Vec<String>,
/// enable TRACE log level
#[argh(switch, short = 'D')]
pub debug: bool,
/// provide password from CLI; if you need to provide multiple passwords, use multiple -P flags.
/// In case just respect the order of the addresses
#[argh(option, short = 'P')]
pub password: Vec<String>,
/// disable logging
#[argh(switch, short = 'q')]
pub quiet: bool,
/// set UI ticks; default 10ms
#[argh(option, short = 'T', default = "10")]
pub ticks: u64,
/// print version
#[argh(switch, short = 'v')]
pub version: bool,
/// disable keyring support
#[argh(switch)]
pub wno_keyring: bool,
// -- positional
#[argh(positional, description = "address1 address2 local-wrkdir")]
pub positional: Vec<String>,
}
#[derive(FromArgs)]
#[argh(subcommand)]
pub enum ArgsSubcommands {
Config(ConfigArgs),
ImportSshHosts(ImportSshHostsArgs),
ImportTheme(ImportThemeArgs),
Update(UpdateArgs),
}
#[derive(FromArgs)]
/// open termscp configuration
#[argh(subcommand, name = "config")]
pub struct ConfigArgs {}
#[derive(FromArgs)]
/// update termscp to the latest version
#[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<PathBuf>,
}
#[derive(FromArgs)]
/// import the specified theme
#[argh(subcommand, name = "theme")]
pub struct ImportThemeArgs {
#[argh(positional)]
/// theme file
pub theme: PathBuf,
}
pub struct RunOpts {
pub remote: RemoteArgs,
pub keyring: bool,
pub ticks: Duration,
pub log_level: LogLevel,
pub task: Task,
}
impl RunOpts {
pub fn config() -> Self {
Self {
task: Task::Activity(NextActivity::SetupActivity),
..Default::default()
}
}
pub fn update() -> Self {
Self {
task: Task::InstallUpdate,
..Default::default()
}
}
pub fn import_ssh_hosts(ssh_config: Option<PathBuf>, keyring: bool) -> Self {
Self {
task: Task::ImportSshHosts(ssh_config),
keyring,
..Default::default()
}
}
pub fn import_theme(theme: PathBuf) -> Self {
Self {
task: Task::ImportTheme(theme),
..Default::default()
}
}
}
impl Default for RunOpts {
fn default() -> Self {
Self {
remote: RemoteArgs::default(),
ticks: Duration::from_millis(10),
keyring: true,
log_level: LogLevel::Info,
task: Task::Activity(NextActivity::Authentication),
}
}
}

271
src/cli/remote.rs Normal file
View File

@@ -0,0 +1,271 @@
use std::path::{Path, PathBuf};
use super::Args;
use crate::filetransfer::FileTransferParams;
use crate::utils;
/// Address type
enum AddrType {
Address,
Bookmark,
}
/// Args for remote connection
#[derive(Debug)]
pub struct RemoteArgs {
pub host_bridge: Remote,
pub remote: Remote,
pub local_dir: Option<PathBuf>,
}
impl Default for RemoteArgs {
fn default() -> Self {
Self {
host_bridge: Remote::None,
remote: Remote::None,
local_dir: None,
}
}
}
impl TryFrom<&Args> for RemoteArgs {
type Error = String;
fn try_from(args: &Args) -> Result<Self, Self::Error> {
let mut remote_args = RemoteArgs::default();
// validate arguments
match (args.bookmark.len(), args.positional.len()) {
(0, positional) if positional < 4 => Ok(()),
(1, positional) if positional < 3 => Ok(()),
(2, positional) if positional < 2 => Ok(()),
(_, _) => Err("Too many arguments".to_string()),
}?;
// parse bookmark first
let last_item_index = (args.bookmark.len() + args.positional.len())
.checked_sub(1)
.unwrap_or_default();
let mut hosts = vec![];
for (i, (addr_type, arg)) in args
.bookmark
.iter()
.map(|x| (AddrType::Bookmark, x))
.chain(args.positional.iter().map(|x| (AddrType::Address, x)))
.enumerate()
{
// check if has password
let password = args.password.get(i).cloned();
// check if is last item and so a possible local dir
if i == last_item_index && Path::new(arg).exists() {
remote_args.local_dir = Some(PathBuf::from(arg));
continue;
}
let remote = match addr_type {
AddrType::Address => Self::parse_remote_address(arg)
.map(|x| Remote::Host(HostParams::new(x, password)))?,
AddrType::Bookmark => Remote::Bookmark(BookmarkParams::new(arg, password.as_ref())),
};
// set remote
hosts.push(remote);
}
// set args based on hosts len
if hosts.len() == 1 {
remote_args.remote = hosts.pop().unwrap();
} else if hosts.len() == 2 {
remote_args.host_bridge = hosts.pop().unwrap();
remote_args.remote = hosts.pop().unwrap();
}
Ok(remote_args)
}
}
impl RemoteArgs {
/// Parse remote address
fn parse_remote_address(remote: &str) -> Result<FileTransferParams, String> {
utils::parser::parse_remote_opt(remote).map_err(|e| format!("Bad address option: {e}"))
}
}
/// Remote argument type
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
pub enum Remote {
/// Bookmark name argument
Bookmark(BookmarkParams),
/// Host argument
Host(HostParams),
/// Unspecified
None,
}
impl Remote {
pub fn is_none(&self) -> bool {
matches!(self, Self::None)
}
}
/// Bookmark parameters
#[derive(Debug)]
pub struct BookmarkParams {
/// bookmark name
pub name: String,
/// bookmark password
pub password: Option<String>,
}
/// Host parameters
#[derive(Debug)]
pub struct HostParams {
/// file transfer parameters
pub file_transfer_params: FileTransferParams,
/// host password specified in arguments
pub password: Option<String>,
}
impl BookmarkParams {
pub fn new<S: AsRef<str>>(name: S, password: Option<S>) -> Self {
Self {
name: name.as_ref().to_string(),
password: password.map(|x| x.as_ref().to_string()),
}
}
}
impl HostParams {
pub fn new<S: AsRef<str>>(params: FileTransferParams, password: Option<S>) -> Self {
Self {
file_transfer_params: params,
password: password.map(|x| x.as_ref().to_string()),
}
}
}
#[cfg(test)]
mod test {
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn test_should_make_remote_args_from_args_one_remote() {
let args = Args {
positional: vec!["scp://host1".to_string()],
..Default::default()
};
let remote_args = RemoteArgs::try_from(&args).unwrap();
assert!(matches!(remote_args.host_bridge, Remote::None));
assert!(matches!(remote_args.remote, Remote::Host(_)));
assert_eq!(remote_args.local_dir, None);
}
#[test]
fn test_should_make_remote_args_from_args_two_remotes() {
let args = Args {
positional: vec!["scp://host1".to_string(), "scp://host2".to_string()],
..Default::default()
};
let remote_args = RemoteArgs::try_from(&args).unwrap();
assert!(matches!(remote_args.host_bridge, Remote::Host(_)));
assert!(matches!(remote_args.remote, Remote::Host(_)));
assert_eq!(remote_args.local_dir, None);
}
#[test]
#[cfg(posix)]
fn test_should_make_remote_args_from_two_remotes_and_local_dir() {
let args = Args {
positional: vec![
"scp://host1".to_string(),
"scp://host2".to_string(),
"/home".to_string(),
],
..Default::default()
};
let remote_args = RemoteArgs::try_from(&args).unwrap();
assert!(matches!(remote_args.host_bridge, Remote::Host(_)));
assert!(matches!(remote_args.remote, Remote::Host(_)));
assert_eq!(remote_args.local_dir, Some(PathBuf::from("/home")));
}
#[test]
fn test_should_make_remote_args_from_args_one_bookmarks() {
let args = Args {
bookmark: vec!["foo".to_string()],
..Default::default()
};
let remote_args = RemoteArgs::try_from(&args).unwrap();
assert!(matches!(remote_args.host_bridge, Remote::None));
assert!(matches!(remote_args.remote, Remote::Bookmark(_)));
assert_eq!(remote_args.local_dir, None);
}
#[test]
fn test_should_make_remote_args_from_args_two_bookmarks() {
let args = Args {
bookmark: vec!["foo".to_string(), "bar".to_string()],
..Default::default()
};
let remote_args = RemoteArgs::try_from(&args).unwrap();
assert!(matches!(remote_args.host_bridge, Remote::Bookmark(_)));
assert!(matches!(remote_args.remote, Remote::Bookmark(_)));
assert_eq!(remote_args.local_dir, None);
}
#[test]
#[cfg(posix)]
fn test_should_make_remote_args_from_two_bookmarks_and_local_dir() {
let args = Args {
bookmark: vec!["foo".to_string(), "bar".to_string()],
positional: vec!["/home".to_string()],
..Default::default()
};
let remote_args = RemoteArgs::try_from(&args).unwrap();
assert!(matches!(remote_args.host_bridge, Remote::Bookmark(_)));
assert!(matches!(remote_args.remote, Remote::Bookmark(_)));
assert_eq!(remote_args.local_dir, Some(PathBuf::from("/home")));
}
#[test]
fn test_should_make_remote_args_from_one_bookmark_and_one_remote() {
let args = Args {
bookmark: vec!["foo".to_string()],
positional: vec!["scp://host1".to_string()],
..Default::default()
};
let remote_args = RemoteArgs::try_from(&args).unwrap();
assert!(matches!(remote_args.host_bridge, Remote::Host(_)));
assert!(matches!(remote_args.remote, Remote::Bookmark(_)));
assert_eq!(remote_args.local_dir, None);
}
#[test]
#[cfg(posix)]
fn test_should_make_remote_args_from_one_bookmark_and_one_remote_with_local_dir() {
let args = Args {
positional: vec!["scp://host1".to_string(), "/home".to_string()],
bookmark: vec!["foo".to_string()],
..Default::default()
};
let remote_args = RemoteArgs::try_from(&args).unwrap();
assert!(matches!(remote_args.host_bridge, Remote::Host(_)));
assert!(matches!(remote_args.remote, Remote::Bookmark(_)));
assert_eq!(remote_args.local_dir, Some(PathBuf::from("/home")));
}
}

View File

@@ -2,36 +2,26 @@
//!
//! `bookmarks` is the module which provides data types and de/serializer for bookmarks
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::filetransfer::params::{AwsS3Params, GenericProtocolParams, ProtocolParams};
use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
mod aws_s3;
mod kube;
mod smb;
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
use std::collections::HashMap;
use std::path::PathBuf;
use std::str::FromStr;
use serde::de::Error as DeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub use self::aws_s3::S3Params;
pub use self::kube::KubeParams;
pub use self::smb::SmbParams;
use crate::filetransfer::params::{
AwsS3Params, GenericProtocolParams, KubeProtocolParams, ProtocolParams,
SmbParams as TransferSmbParams, WebDAVProtocolParams,
};
use crate::filetransfer::{FileTransferParams, FileTransferProtocol};
/// UserHosts contains all the hosts saved by the user in the data storage
/// It contains both `Bookmark`
#[derive(Deserialize, Serialize, Debug, Default)]
@@ -41,7 +31,7 @@ pub struct UserHosts {
}
/// Bookmark describes a single bookmark entry in the user hosts storage
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq)]
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq)]
pub struct Bookmark {
#[serde(
deserialize_with = "deserialize_protocol",
@@ -56,25 +46,26 @@ pub struct Bookmark {
pub username: Option<String>,
/// Password is optional; base64, aes-128 encrypted password
pub password: Option<String>,
/// Remote folder to connect to (serde rename for legacy reasons)
#[serde(rename = "directory")]
pub remote_path: Option<PathBuf>,
/// local folder to open at startup
pub local_path: Option<PathBuf>,
/// Kube params; optional. When used other fields are empty for sure
pub kube: Option<KubeParams>,
/// S3 params; optional. When used other fields are empty for sure
pub s3: Option<S3Params>,
}
/// Connection parameters for Aws s3 protocol
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Default)]
pub struct S3Params {
pub bucket: String,
pub region: String,
pub profile: Option<String>,
pub access_key: Option<String>,
pub secret_access_key: Option<String>,
/// SMB params; optional. Extra params required for SMB protocol
pub smb: Option<SmbParams>,
}
// -- impls
impl From<FileTransferParams> for Bookmark {
fn from(params: FileTransferParams) -> Self {
let protocol: FileTransferProtocol = params.protocol;
let protocol = params.protocol;
let remote_path = params.remote_path;
let local_path = params.local_path;
// Create generic or others
match params.params {
ProtocolParams::Generic(params) => Self {
@@ -83,7 +74,11 @@ impl From<FileTransferParams> for Bookmark {
port: Some(params.port),
username: params.username,
password: params.password,
remote_path,
local_path,
kube: None,
s3: None,
smb: None,
},
ProtocolParams::AwsS3(params) => Self {
protocol,
@@ -91,7 +86,50 @@ impl From<FileTransferParams> for Bookmark {
port: None,
username: None,
password: None,
remote_path,
local_path,
kube: None,
s3: Some(S3Params::from(params)),
smb: None,
},
ProtocolParams::Kube(params) => Self {
protocol,
address: None,
port: None,
username: None,
password: None,
remote_path,
local_path,
kube: Some(KubeParams::from(params)),
s3: None,
smb: None,
},
ProtocolParams::Smb(params) => Self {
smb: Some(SmbParams::from(params.clone())),
protocol,
address: Some(params.address),
#[cfg(posix)]
port: Some(params.port),
#[cfg(win)]
port: None,
username: params.username,
password: params.password,
remote_path,
local_path,
kube: None,
s3: None,
},
ProtocolParams::WebDAV(parms) => Self {
protocol,
address: Some(parms.uri),
port: None,
username: Some(parms.username),
password: Some(parms.password),
remote_path,
local_path,
kube: None,
s3: None,
smb: None,
},
}
}
@@ -106,35 +144,56 @@ impl From<Bookmark> for FileTransferParams {
let params = AwsS3Params::from(params);
Self::new(FileTransferProtocol::AwsS3, ProtocolParams::AwsS3(params))
}
protocol => {
FileTransferProtocol::Ftp(_)
| FileTransferProtocol::Scp
| FileTransferProtocol::Sftp => {
let params = GenericProtocolParams::default()
.address(bookmark.address.unwrap_or_default())
.port(bookmark.port.unwrap_or(22))
.username(bookmark.username)
.password(bookmark.password);
Self::new(protocol, ProtocolParams::Generic(params))
Self::new(bookmark.protocol, ProtocolParams::Generic(params))
}
}
}
}
FileTransferProtocol::Kube => {
let params = bookmark.kube.unwrap_or_default();
let params = KubeProtocolParams::from(params);
Self::new(bookmark.protocol, ProtocolParams::Kube(params))
}
#[cfg(posix)]
FileTransferProtocol::Smb => {
let params = TransferSmbParams::new(
bookmark.address.unwrap_or_default(),
bookmark.smb.clone().map(|x| x.share).unwrap_or_default(),
)
.port(bookmark.port.unwrap_or(445))
.username(bookmark.username)
.password(bookmark.password)
.workgroup(bookmark.smb.and_then(|x| x.workgroup));
impl From<AwsS3Params> for S3Params {
fn from(params: AwsS3Params) -> Self {
S3Params {
bucket: params.bucket_name,
region: params.region,
profile: params.profile,
access_key: params.access_key,
secret_access_key: params.secret_access_key,
}
}
}
Self::new(bookmark.protocol, ProtocolParams::Smb(params))
}
#[cfg(win)]
FileTransferProtocol::Smb => {
let params = TransferSmbParams::new(
bookmark.address.unwrap_or_default(),
bookmark.smb.clone().map(|x| x.share).unwrap_or_default(),
)
.username(bookmark.username)
.password(bookmark.password);
impl From<S3Params> for AwsS3Params {
fn from(params: S3Params) -> Self {
AwsS3Params::new(params.bucket, params.region, params.profile)
.access_key(params.access_key)
.secret_access_key(params.secret_access_key)
Self::new(bookmark.protocol, ProtocolParams::Smb(params))
}
FileTransferProtocol::WebDAV => Self::new(
FileTransferProtocol::WebDAV,
ProtocolParams::WebDAV(WebDAVProtocolParams {
uri: bookmark.address.unwrap_or_default(),
username: bookmark.username.unwrap_or_default(),
password: bookmark.password.unwrap_or_default(),
}),
),
}
.remote_path(bookmark.remote_path) // Set entry remote_path
.local_path(bookmark.local_path) // Set entry local path
}
}
@@ -142,9 +201,9 @@ fn deserialize_protocol<'de, D>(deserializer: D) -> Result<FileTransferProtocol,
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
let s: String = Deserialize::deserialize(deserializer)?;
// Parse color
match FileTransferProtocol::from_str(s) {
match FileTransferProtocol::from_str(&s) {
Err(err) => Err(DeError::custom(err)),
Ok(protocol) => Ok(protocol),
}
@@ -162,9 +221,10 @@ where
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn test_bookmarks_default() {
let bookmarks: UserHosts = UserHosts::default();
@@ -180,7 +240,11 @@ mod tests {
protocol: FileTransferProtocol::Sftp,
username: Some(String::from("root")),
password: Some(String::from("password")),
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
kube: None,
s3: None,
smb: None,
};
let recent: Bookmark = Bookmark {
address: Some(String::from("192.168.1.2")),
@@ -188,7 +252,11 @@ mod tests {
protocol: FileTransferProtocol::Scp,
username: Some(String::from("admin")),
password: Some(String::from("password")),
remote_path: Some(PathBuf::from("/home")),
local_path: Some(PathBuf::from("/usr")),
kube: None,
s3: None,
smb: None,
};
let mut bookmarks: HashMap<String, Bookmark> = HashMap::with_capacity(1);
bookmarks.insert(String::from("test"), bookmark);
@@ -202,6 +270,14 @@ mod tests {
assert_eq!(bookmark.protocol, FileTransferProtocol::Sftp);
assert_eq!(bookmark.username.as_deref().unwrap(), "root");
assert_eq!(bookmark.password.as_deref().unwrap(), "password");
assert_eq!(
bookmark.remote_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
assert_eq!(
bookmark.local_path.as_deref().unwrap(),
std::path::Path::new("/usr")
);
let bookmark: &Bookmark = hosts
.recents
.get(&String::from("ISO20201218T181432"))
@@ -211,6 +287,14 @@ mod tests {
assert_eq!(bookmark.protocol, FileTransferProtocol::Scp);
assert_eq!(bookmark.username.as_deref().unwrap(), "admin");
assert_eq!(bookmark.password.as_deref().unwrap(), "password");
assert_eq!(
bookmark.remote_path.as_deref().unwrap(),
std::path::Path::new("/home")
);
assert_eq!(
bookmark.local_path.as_deref().unwrap(),
std::path::Path::new("/usr")
);
}
#[test]
@@ -221,20 +305,30 @@ mod tests {
username: Some(String::from("root")),
password: Some(String::from("omar")),
});
let params: FileTransferParams = FileTransferParams::new(FileTransferProtocol::Scp, params);
let params: FileTransferParams = FileTransferParams::new(FileTransferProtocol::Scp, params)
.remote_path(Some(PathBuf::from("/home")))
.local_path(Some(PathBuf::from("/tmp")));
let bookmark = Bookmark::from(params);
assert_eq!(bookmark.protocol, FileTransferProtocol::Scp);
assert_eq!(bookmark.address.as_deref().unwrap(), "127.0.0.1");
assert_eq!(bookmark.port.unwrap(), 10222);
assert_eq!(bookmark.username.as_deref().unwrap(), "root");
assert_eq!(bookmark.password.as_deref().unwrap(), "omar");
assert_eq!(
bookmark.remote_path.as_deref().unwrap(),
std::path::Path::new("/home")
);
assert_eq!(
bookmark.local_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
assert!(bookmark.s3.is_none());
}
#[test]
fn bookmark_from_s3_ftparams() {
let params = ProtocolParams::AwsS3(
AwsS3Params::new("omar", "eu-west-1", Some("test"))
AwsS3Params::new("omar", Some("eu-west-1"), Some("test"))
.access_key(Some("pippo"))
.secret_access_key(Some("pluto")),
);
@@ -248,12 +342,40 @@ mod tests {
assert!(bookmark.password.is_none());
let s3: &S3Params = bookmark.s3.as_ref().unwrap();
assert_eq!(s3.bucket.as_str(), "omar");
assert_eq!(s3.region.as_str(), "eu-west-1");
assert_eq!(s3.region.as_deref().unwrap(), "eu-west-1");
assert_eq!(s3.profile.as_deref().unwrap(), "test");
assert_eq!(s3.access_key.as_deref().unwrap(), "pippo");
assert_eq!(s3.secret_access_key.as_deref().unwrap(), "pluto");
}
#[test]
fn bookmark_from_kube_ftparams() {
let params = ProtocolParams::Kube(KubeProtocolParams {
namespace: Some("default".to_string()),
username: Some("root".to_string()),
cluster_url: Some("https://localhost:6443".to_string()),
client_cert: Some("cert".to_string()),
client_key: Some("key".to_string()),
});
let params: FileTransferParams =
FileTransferParams::new(FileTransferProtocol::Kube, params);
let bookmark = Bookmark::from(params);
assert_eq!(bookmark.protocol, FileTransferProtocol::Kube);
assert!(bookmark.address.is_none());
assert!(bookmark.port.is_none());
assert!(bookmark.username.is_none());
assert!(bookmark.password.is_none());
let kube: &KubeParams = bookmark.kube.as_ref().unwrap();
assert_eq!(kube.namespace.as_deref().unwrap(), "default");
assert_eq!(
kube.cluster_url.as_deref().unwrap(),
"https://localhost:6443"
);
assert_eq!(kube.username.as_deref().unwrap(), "root");
assert_eq!(kube.client_cert.as_deref().unwrap(), "cert");
assert_eq!(kube.client_key.as_deref().unwrap(), "key");
}
#[test]
fn ftparams_from_generic_bookmark() {
let bookmark: Bookmark = Bookmark {
@@ -262,10 +384,22 @@ mod tests {
protocol: FileTransferProtocol::Sftp,
username: Some(String::from("root")),
password: Some(String::from("password")),
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
kube: None,
s3: None,
smb: None,
};
let params = FileTransferParams::from(bookmark);
assert_eq!(params.protocol, FileTransferProtocol::Sftp);
assert_eq!(
params.remote_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
assert_eq!(
params.local_path.as_deref().unwrap(),
std::path::Path::new("/usr")
);
let gparams = params.params.generic_params().unwrap();
assert_eq!(gparams.address.as_str(), "192.168.1.1");
assert_eq!(gparams.port, 22);
@@ -273,6 +407,36 @@ mod tests {
assert_eq!(gparams.password.as_deref().unwrap(), "password");
}
#[test]
fn ftparams_from_webdav() {
let bookmark: Bookmark = Bookmark {
address: Some(String::from("192.168.1.1")),
port: None,
protocol: FileTransferProtocol::WebDAV,
username: Some(String::from("root")),
password: Some(String::from("password")),
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
kube: None,
s3: None,
smb: None,
};
let params = FileTransferParams::from(bookmark);
assert_eq!(params.protocol, FileTransferProtocol::WebDAV);
assert_eq!(
params.remote_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
assert_eq!(
params.local_path.as_deref().unwrap(),
std::path::Path::new("/usr")
);
let gparams = params.params.webdav_params().unwrap();
assert_eq!(gparams.uri.as_str(), "192.168.1.1");
assert_eq!(gparams.username, "root");
assert_eq!(gparams.password, "password");
}
#[test]
fn ftparams_from_s3_bookmark() {
let bookmark: Bookmark = Bookmark {
@@ -281,21 +445,150 @@ mod tests {
port: None,
username: None,
password: None,
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
kube: None,
s3: Some(S3Params {
bucket: String::from("veeso"),
region: String::from("eu-west-1"),
region: Some(String::from("eu-west-1")),
endpoint: Some(String::from("omar")),
profile: Some(String::from("default")),
access_key: Some(String::from("pippo")),
secret_access_key: Some(String::from("pluto")),
new_path_style: Some(true),
}),
smb: None,
};
let params = FileTransferParams::from(bookmark);
assert_eq!(params.protocol, FileTransferProtocol::AwsS3);
assert_eq!(
params.remote_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
assert_eq!(
params.local_path.as_deref().unwrap(),
std::path::Path::new("/usr")
);
let gparams = params.params.s3_params().unwrap();
assert_eq!(gparams.bucket_name.as_str(), "veeso");
assert_eq!(gparams.region.as_str(), "eu-west-1");
assert_eq!(gparams.region.as_deref().unwrap(), "eu-west-1");
assert_eq!(gparams.endpoint.as_deref().unwrap(), "omar");
assert_eq!(gparams.profile.as_deref().unwrap(), "default");
assert_eq!(gparams.access_key.as_deref().unwrap(), "pippo");
assert_eq!(gparams.secret_access_key.as_deref().unwrap(), "pluto");
assert_eq!(gparams.new_path_style, true);
}
#[test]
fn ftparams_from_kube_bookmark() {
let bookmark: Bookmark = Bookmark {
protocol: FileTransferProtocol::Kube,
address: None,
port: None,
username: None,
password: None,
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
kube: Some(KubeParams {
namespace: Some(String::from("default")),
cluster_url: Some(String::from("https://localhost:6443")),
username: Some(String::from("root")),
client_cert: Some(String::from("cert")),
client_key: Some(String::from("key")),
}),
s3: None,
smb: None,
};
let params = FileTransferParams::from(bookmark);
assert_eq!(params.protocol, FileTransferProtocol::Kube);
assert_eq!(
params.remote_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
assert_eq!(
params.local_path.as_deref().unwrap(),
std::path::Path::new("/usr")
);
let gparams = params.params.kube_params().unwrap();
assert_eq!(gparams.namespace.as_deref().unwrap(), "default");
assert_eq!(
gparams.cluster_url.as_deref().unwrap(),
"https://localhost:6443"
);
assert_eq!(gparams.username.as_deref().unwrap(), "root");
assert_eq!(gparams.client_cert.as_deref().unwrap(), "cert");
assert_eq!(gparams.client_key.as_deref().unwrap(), "key");
}
#[test]
#[cfg(posix)]
fn should_get_ftparams_from_smb_bookmark() {
let bookmark: Bookmark = Bookmark {
protocol: FileTransferProtocol::Smb,
address: Some("localhost".to_string()),
port: Some(445),
username: Some("foo".to_string()),
password: Some("bar".to_string()),
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
kube: None,
s3: None,
smb: Some(SmbParams {
share: "test".to_string(),
workgroup: Some("testone".to_string()),
}),
};
let params = FileTransferParams::from(bookmark);
assert_eq!(params.protocol, FileTransferProtocol::Smb);
assert_eq!(
params.remote_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
assert_eq!(
params.local_path.as_deref().unwrap(),
std::path::Path::new("/usr")
);
let smb_params = params.params.smb_params().unwrap();
assert_eq!(smb_params.address.as_str(), "localhost");
assert_eq!(smb_params.port, 445);
assert_eq!(smb_params.share.as_str(), "test");
assert_eq!(smb_params.password.as_deref().unwrap(), "bar");
assert_eq!(smb_params.username.as_deref().unwrap(), "foo");
assert_eq!(smb_params.workgroup.as_deref().unwrap(), "testone");
}
#[test]
#[cfg(win)]
fn should_get_ftparams_from_smb_bookmark() {
let bookmark: Bookmark = Bookmark {
protocol: FileTransferProtocol::Smb,
address: Some("localhost".to_string()),
port: Some(445),
username: None,
password: None,
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
s3: None,
kube: None,
smb: Some(SmbParams {
share: "test".to_string(),
workgroup: None,
}),
};
let params = FileTransferParams::from(bookmark);
assert_eq!(params.protocol, FileTransferProtocol::Smb);
assert_eq!(
params.remote_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
assert_eq!(
params.local_path.as_deref().unwrap(),
std::path::Path::new("/usr")
);
let smb_params = params.params.smb_params().unwrap();
assert_eq!(smb_params.address.as_str(), "localhost");
assert_eq!(smb_params.share.as_str(), "test");
}
}

View File

@@ -0,0 +1,40 @@
use serde::{Deserialize, Serialize};
use crate::filetransfer::params::AwsS3Params;
/// Connection parameters for Aws s3 protocol
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
pub struct S3Params {
pub bucket: String,
pub region: Option<String>,
pub endpoint: Option<String>,
pub profile: Option<String>,
pub access_key: Option<String>,
pub secret_access_key: Option<String>,
/// NOTE: there are no session token and security token since they are always temporary
pub new_path_style: Option<bool>,
}
impl From<AwsS3Params> for S3Params {
fn from(params: AwsS3Params) -> Self {
S3Params {
bucket: params.bucket_name,
region: params.region,
endpoint: params.endpoint,
profile: params.profile,
access_key: params.access_key,
secret_access_key: params.secret_access_key,
new_path_style: Some(params.new_path_style),
}
}
}
impl From<S3Params> for AwsS3Params {
fn from(params: S3Params) -> Self {
AwsS3Params::new(params.bucket, params.region, params.profile)
.endpoint(params.endpoint)
.access_key(params.access_key)
.secret_access_key(params.secret_access_key)
.new_path_style(params.new_path_style.unwrap_or(false))
}
}

View File

@@ -0,0 +1,37 @@
use serde::{Deserialize, Serialize};
use crate::filetransfer::params::KubeProtocolParams;
/// Extra Connection parameters for Kube protocol
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
pub struct KubeParams {
pub namespace: Option<String>,
pub cluster_url: Option<String>,
pub username: Option<String>,
pub client_cert: Option<String>,
pub client_key: Option<String>,
}
impl From<KubeParams> for KubeProtocolParams {
fn from(value: KubeParams) -> Self {
Self {
namespace: value.namespace,
cluster_url: value.cluster_url,
username: value.username,
client_cert: value.client_cert,
client_key: value.client_key,
}
}
}
impl From<KubeProtocolParams> for KubeParams {
fn from(value: KubeProtocolParams) -> Self {
Self {
namespace: value.namespace,
cluster_url: value.cluster_url,
username: value.username,
client_cert: value.client_cert,
client_key: value.client_key,
}
}
}

View File

@@ -0,0 +1,30 @@
use serde::{Deserialize, Serialize};
use crate::filetransfer::params::SmbParams as TransferSmbParams;
/// Extra Connection parameters for SMB protocol
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Default)]
pub struct SmbParams {
pub share: String,
pub workgroup: Option<String>,
}
#[cfg(posix)]
impl From<TransferSmbParams> for SmbParams {
fn from(params: TransferSmbParams) -> Self {
Self {
share: params.share,
workgroup: params.workgroup,
}
}
}
#[cfg(win)]
impl From<TransferSmbParams> for SmbParams {
fn from(params: TransferSmbParams) -> Self {
Self {
share: params.share,
workgroup: None,
}
}
}

View File

@@ -2,31 +2,7 @@
//!
//! `config` is the module which provides access to all the termscp configurations
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// export
pub use params::*;
pub mod bookmarks;
pub mod params;

View File

@@ -2,36 +2,14 @@
//!
//! `config` is the module which provides access to termscp configuration
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// Locals
use crate::filetransfer::FileTransferProtocol;
use std::collections::HashMap;
use std::path::PathBuf;
// Ext
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
use crate::filetransfer::FileTransferProtocol;
pub const DEFAULT_NOTIFICATION_TRANSFER_THRESHOLD: u64 = 536870912; // 512MB
@@ -59,7 +37,7 @@ pub struct UserInterfaceConfig {
pub notification_threshold: Option<u64>, // @! Since 0.7.0; Default 512MB
}
#[derive(Deserialize, Serialize, Debug, Default)]
#[derive(Deserialize, Serialize, Debug)]
/// Contains configuratio related to remote hosts
pub struct RemoteConfig {
/// Ssh configuration path. If NONE, won't be read
@@ -69,6 +47,26 @@ pub struct RemoteConfig {
pub ssh_keys: HashMap<String, PathBuf>,
}
impl Default for RemoteConfig {
fn default() -> Self {
let home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("/root"));
let mut ssh_config_path = "~/.ssh/config".to_string();
ssh_config_path = ssh_config_path.replacen('~', &home_dir.to_string_lossy(), 1);
// check if ssh config path exists first
let ssh_config_path = if PathBuf::from(&ssh_config_path).exists() {
Some(ssh_config_path)
} else {
None
};
Self {
ssh_config: ssh_config_path,
ssh_keys: HashMap::default(),
}
}
}
impl Default for UserInterfaceConfig {
fn default() -> Self {
UserInterfaceConfig {
@@ -94,9 +92,10 @@ impl Default for UserInterfaceConfig {
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn test_config_mod_new() {
let mut keys: HashMap<String, PathBuf> = HashMap::with_capacity(1);
@@ -129,7 +128,7 @@ mod tests {
assert_eq!(ui.file_fmt, Some(String::from("{NAME}")));
let cfg: UserConfig = UserConfig {
user_interface: ui,
remote: remote,
remote,
};
assert_eq!(
*cfg.remote

View File

@@ -2,31 +2,10 @@
//!
//! `serialization` provides serialization and deserialization for configurations
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use serde::{de::DeserializeOwned, Serialize};
use std::io::{Read, Write};
use serde::Serialize;
use serde::de::DeserializeOwned;
use thiserror::Error;
/// Contains the error for serializer/deserializer
@@ -72,8 +51,6 @@ impl std::fmt::Display for SerializerError {
}
}
/// ### serialize
///
/// Serialize `UserHosts` into TOML and write content to writable
pub fn serialize<S>(serializable: &S, mut writable: Box<dyn Write>) -> Result<(), SerializerError>
where
@@ -86,7 +63,7 @@ where
return Err(SerializerError::new_ex(
SerializerErrorKind::Serialization,
err.to_string(),
))
));
}
};
trace!("Serialized new bookmarks data: {}", data);
@@ -100,8 +77,6 @@ where
}
}
/// ### deserialize
///
/// Read data from readable and deserialize its content as TOML
pub fn deserialize<S>(mut readable: Box<dyn Read>) -> Result<S, SerializerError>
where
@@ -132,30 +107,30 @@ where
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
use std::io::Seek;
use std::path::PathBuf;
use crate::config::bookmarks::{Bookmark, S3Params, UserHosts};
use pretty_assertions::assert_eq;
use tuirealm::ratatui::style::Color;
use super::*;
use crate::config::bookmarks::{Bookmark, KubeParams, S3Params, SmbParams, UserHosts};
use crate::config::params::UserConfig;
use crate::config::themes::Theme;
use crate::filetransfer::FileTransferProtocol;
use crate::utils::test_helpers::create_file_ioers;
use pretty_assertions::assert_eq;
use std::collections::HashMap;
use std::io::{Seek, SeekFrom};
use std::path::PathBuf;
use tuirealm::tui::style::Color;
#[test]
fn test_config_serialization_errors() {
let error: SerializerError = SerializerError::new(SerializerErrorKind::Syntax);
assert!(error.msg.is_none());
assert_eq!(format!("{}", error), String::from("Syntax error"));
assert_eq!(format!("{error}"), String::from("Syntax error"));
let error: SerializerError =
SerializerError::new_ex(SerializerErrorKind::Syntax, String::from("bad syntax"));
assert!(error.msg.is_some());
assert_eq!(
format!("{}", error),
format!("{error}"),
String::from("Syntax error (bad syntax)")
);
// Fmt
@@ -182,7 +157,7 @@ mod tests {
fn test_config_serialization_params_deserialize_ok() {
let toml_file: tempfile::NamedTempFile = create_good_toml_bookmarks_params();
toml_file.as_file().sync_all().unwrap();
toml_file.as_file().seek(SeekFrom::Start(0)).unwrap();
toml_file.as_file().rewind().unwrap();
// Parse
let cfg = deserialize(Box::new(toml_file));
assert!(cfg.is_ok());
@@ -232,7 +207,7 @@ mod tests {
fn test_config_serialization_params_deserialize_ok_no_opts() {
let toml_file: tempfile::NamedTempFile = create_good_toml_bookmarks_params_no_opts();
toml_file.as_file().sync_all().unwrap();
toml_file.as_file().seek(SeekFrom::Start(0)).unwrap();
toml_file.as_file().rewind().unwrap();
// Parse
let cfg = deserialize(Box::new(toml_file));
assert!(cfg.is_ok());
@@ -272,7 +247,7 @@ mod tests {
fn test_config_serialization_params_deserialize_nok() {
let toml_file: tempfile::NamedTempFile = create_bad_toml_bookmarks_params();
toml_file.as_file().sync_all().unwrap();
toml_file.as_file().seek(SeekFrom::Start(0)).unwrap();
toml_file.as_file().rewind().unwrap();
// Parse
assert!(deserialize::<UserConfig>(Box::new(toml_file)).is_err());
}
@@ -291,7 +266,7 @@ mod tests {
assert!(serialize(&cfg, writer).is_ok());
// Reload configuration and check if it's ok
toml_file.as_file().sync_all().unwrap();
toml_file.as_file().seek(SeekFrom::Start(0)).unwrap();
toml_file.as_file().rewind().unwrap();
assert!(deserialize::<UserConfig>(Box::new(toml_file)).is_ok());
}
@@ -376,7 +351,7 @@ mod tests {
fn test_config_serializer_bookmarks_serializer_deserialize_ok() {
let toml_file: tempfile::NamedTempFile = create_good_toml_bookmarks();
toml_file.as_file().sync_all().unwrap();
toml_file.as_file().seek(SeekFrom::Start(0)).unwrap();
toml_file.as_file().rewind().unwrap();
// Parse
let hosts = deserialize(Box::new(toml_file));
assert!(hosts.is_ok());
@@ -391,7 +366,7 @@ mod tests {
assert_eq!(host.username.as_deref().unwrap(), "root");
assert_eq!(host.password, None);
// Verify bookmarks
assert_eq!(hosts.bookmarks.len(), 4);
assert_eq!(hosts.bookmarks.len(), 6);
let host: &Bookmark = hosts.bookmarks.get("raspberrypi2").unwrap();
assert_eq!(host.address.as_deref().unwrap(), "192.168.1.31");
assert_eq!(host.port.unwrap(), 22);
@@ -404,6 +379,10 @@ mod tests {
assert_eq!(host.protocol, FileTransferProtocol::Sftp);
assert_eq!(host.username.as_deref().unwrap(), "cvisintin");
assert_eq!(host.password.as_deref().unwrap(), "mysecret");
assert_eq!(
host.remote_path.as_deref().unwrap(),
std::path::Path::new("/tmp")
);
let host: &Bookmark = hosts.bookmarks.get("aws-server-prod1").unwrap();
assert_eq!(host.address.as_deref().unwrap(), "51.23.67.12");
assert_eq!(host.port.unwrap(), 21);
@@ -419,17 +398,46 @@ mod tests {
assert_eq!(host.protocol, FileTransferProtocol::AwsS3);
let s3 = host.s3.as_ref().unwrap();
assert_eq!(s3.bucket.as_str(), "veeso");
assert_eq!(s3.region.as_str(), "eu-west-1");
assert_eq!(s3.region.as_deref().unwrap(), "eu-west-1");
assert_eq!(s3.profile.as_deref().unwrap(), "default");
assert_eq!(s3.endpoint.as_deref().unwrap(), "http://localhost:9000");
assert_eq!(s3.access_key.as_deref().unwrap(), "pippo");
assert_eq!(s3.secret_access_key.as_deref().unwrap(), "pluto");
assert_eq!(s3.new_path_style.unwrap(), true);
// Kube pod
let host: &Bookmark = hosts.bookmarks.get("pod").unwrap();
assert_eq!(host.address, None);
assert_eq!(host.port, None);
assert_eq!(host.username, None);
assert_eq!(host.password, None);
assert_eq!(host.protocol, FileTransferProtocol::Kube);
let kube = host.kube.as_ref().unwrap();
assert_eq!(kube.namespace.as_deref().unwrap(), "my-namespace");
assert_eq!(kube.cluster_url.as_deref().unwrap(), "https://my-cluster");
assert_eq!(kube.username.as_deref().unwrap(), "my-username");
assert_eq!(kube.client_cert.as_deref().unwrap(), "my-cert");
assert_eq!(kube.client_key.as_deref().unwrap(), "my-key");
// smb
let host = hosts.bookmarks.get("smb").unwrap();
assert_eq!(host.address.as_deref().unwrap(), "localhost");
assert_eq!(host.port.unwrap(), 445);
#[cfg(posix)]
assert_eq!(host.username.as_deref().unwrap(), "test");
#[cfg(posix)]
assert_eq!(host.password.as_deref().unwrap(), "test");
let smb = host.smb.as_ref().unwrap();
assert_eq!(smb.share.as_str(), "temp");
#[cfg(posix)]
assert_eq!(smb.workgroup.as_deref().unwrap(), "test");
}
#[test]
fn test_config_serializer_bookmarks_serializer_deserialize_nok() {
let toml_file: tempfile::NamedTempFile = create_bad_toml_bookmarks();
toml_file.as_file().sync_all().unwrap();
toml_file.as_file().seek(SeekFrom::Start(0)).unwrap();
toml_file.as_file().rewind().unwrap();
// Parse
assert!(deserialize::<UserHosts>(Box::new(toml_file)).is_err());
}
@@ -446,7 +454,11 @@ mod tests {
protocol: FileTransferProtocol::Sftp,
username: Some(String::from("root")),
password: None,
remote_path: None,
local_path: None,
kube: None,
s3: None,
smb: None,
},
);
bookmarks.insert(
@@ -457,7 +469,11 @@ mod tests {
protocol: FileTransferProtocol::Sftp,
username: Some(String::from("cvisintin")),
password: Some(String::from("password")),
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
kube: None,
s3: None,
smb: None,
},
);
bookmarks.insert(
@@ -468,13 +484,61 @@ mod tests {
protocol: FileTransferProtocol::AwsS3,
username: None,
password: None,
remote_path: None,
local_path: None,
s3: Some(S3Params {
bucket: "veeso".to_string(),
region: "eu-west-1".to_string(),
region: Some("eu-west-1".to_string()),
endpoint: None,
profile: None,
access_key: None,
secret_access_key: None,
new_path_style: None,
}),
kube: None,
smb: None,
},
);
// push kube pod
bookmarks.insert(
String::from("pod"),
Bookmark {
address: None,
port: None,
protocol: FileTransferProtocol::Kube,
username: None,
password: None,
remote_path: None,
local_path: None,
s3: None,
smb: None,
kube: Some(KubeParams {
namespace: Some("my-namespace".to_string()),
cluster_url: Some("https://my-cluster".to_string()),
username: Some("my-username".to_string()),
client_cert: Some("my-cert".to_string()),
client_key: Some("my-key".to_string()),
}),
},
);
let smb_params: Option<SmbParams> = Some(SmbParams {
share: "test".to_string(),
workgroup: None,
});
bookmarks.insert(
String::from("smb"),
Bookmark {
address: Some("localhost".to_string()),
port: Some(445),
protocol: FileTransferProtocol::Smb,
username: None,
password: None,
remote_path: None,
local_path: None,
s3: None,
kube: None,
smb: smb_params,
},
);
let mut recents: HashMap<String, Bookmark> = HashMap::with_capacity(1);
@@ -486,7 +550,11 @@ mod tests {
protocol: FileTransferProtocol::Scp,
username: Some(String::from("omar")),
password: Some(String::from("aaa")),
remote_path: Some(PathBuf::from("/tmp")),
local_path: Some(PathBuf::from("/usr")),
s3: None,
kube: None,
smb: None,
},
);
let tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap();
@@ -497,8 +565,10 @@ mod tests {
#[test]
fn test_config_serialization_theme_serialize() {
let mut theme: Theme = Theme::default();
theme.auth_address = Color::Rgb(240, 240, 240);
let theme: Theme = Theme {
auth_address: Color::Rgb(240, 240, 240),
..Default::default()
};
let tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap();
let (reader, writer) = create_file_ioers(tmpfile.path());
assert!(serialize(&theme, Box::new(writer)).is_ok());
@@ -511,21 +581,37 @@ mod tests {
fn test_config_serialization_theme_deserialize() {
let toml_file = create_good_toml_theme();
toml_file.as_file().sync_all().unwrap();
toml_file.as_file().seek(SeekFrom::Start(0)).unwrap();
toml_file.as_file().rewind().unwrap();
assert!(deserialize::<Theme>(Box::new(toml_file)).is_ok());
let toml_file = create_bad_toml_theme();
toml_file.as_file().sync_all().unwrap();
toml_file.as_file().seek(SeekFrom::Start(0)).unwrap();
toml_file.as_file().rewind().unwrap();
assert!(deserialize::<Theme>(Box::new(toml_file)).is_err());
}
#[test]
fn test_should_deserialize_v14_pod_bookmark() {
let toml = create_v14_pod_bookmark();
toml.as_file().sync_all().unwrap();
toml.as_file().rewind().unwrap();
let deserialized: UserHosts = deserialize(Box::new(toml)).unwrap();
let kube = deserialized.bookmarks.get("pod").unwrap();
assert_eq!(kube.protocol, FileTransferProtocol::Kube);
let kube = kube.kube.as_ref().unwrap();
assert_eq!(kube.namespace.as_deref().unwrap(), "my-namespace");
assert_eq!(kube.cluster_url.as_deref().unwrap(), "https://my-cluster");
assert_eq!(kube.username.as_deref().unwrap(), "my-username");
assert_eq!(kube.client_cert.as_deref().unwrap(), "my-cert");
assert_eq!(kube.client_key.as_deref().unwrap(), "my-key");
}
fn create_good_toml_bookmarks() -> tempfile::NamedTempFile {
// Write
let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap();
let file_content: &str = r#"
[bookmarks]
raspberrypi2 = { address = "192.168.1.31", port = 22, protocol = "SFTP", username = "root", password = "mypassword" }
msi-estrem = { address = "192.168.1.30", port = 22, protocol = "SFTP", username = "cvisintin", password = "mysecret" }
msi-estrem = { address = "192.168.1.30", port = 22, protocol = "SFTP", username = "cvisintin", password = "mysecret", directory = "/tmp", local_path = "/usr" }
aws-server-prod1 = { address = "51.23.67.12", port = 21, protocol = "FTPS", username = "aws001" }
[bookmarks.my-bucket]
@@ -534,9 +620,31 @@ mod tests {
[bookmarks.my-bucket.s3]
bucket = "veeso"
region = "eu-west-1"
endpoint = "http://localhost:9000"
profile = "default"
access_key = "pippo"
secret_access_key = "pluto"
new_path_style = true
[bookmarks.pod]
protocol = "KUBE"
[bookmarks.pod.kube]
namespace = "my-namespace"
cluster_url = "https://my-cluster"
username = "my-username"
client_cert = "my-cert"
client_key = "my-key"
[bookmarks.smb]
protocol = "SMB"
address = "localhost"
port = 445
username = "test"
password = "test"
[bookmarks.smb.smb]
share = "temp"
workgroup = "test"
[recents]
ISO20201215T094000Z = { address = "172.16.104.10", port = 22, protocol = "SCP", username = "root" }
@@ -546,6 +654,29 @@ mod tests {
tmpfile
}
fn create_v14_pod_bookmark() -> tempfile::NamedTempFile {
let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap();
let file_content: &str = r#"
[bookmarks]
[bookmarks.pod]
protocol = "KUBE"
[bookmarks.pod.kube]
pod_name = "my-pod"
container = "my-container"
namespace = "my-namespace"
cluster_url = "https://my-cluster"
username = "my-username"
client_cert = "my-cert"
client_key = "my-key"
[recents]
"#;
tmpfile.write_all(file_content.as_bytes()).unwrap();
//write!(tmpfile, "[bookmarks]\nraspberrypi2 = {{ address = \"192.168.1.31\", port = 22, protocol = \"SFTP\", username = \"root\" }}\nmsi-estrem = {{ address = \"192.168.1.30\", port = 22, protocol = \"SFTP\", username = \"cvisintin\" }}\naws-server-prod1 = {{ address = \"51.23.67.12\", port = 21, protocol = \"FTPS\", username = \"aws001\" }}\n\n[recents]\nISO20201215T094000Z = {{ address = \"172.16.104.10\", port = 22, protocol = \"SCP\", username = \"root\" }}\n");
tmpfile
}
fn create_bad_toml_bookmarks() -> tempfile::NamedTempFile {
// Write
let mut tmpfile: tempfile::NamedTempFile = tempfile::NamedTempFile::new().unwrap();

View File

@@ -2,40 +2,17 @@
//!
//! `themes` is the module which provides the themes configurations and the serializers
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// locals
// ext
use serde::de::Error as DeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use tuirealm::ratatui::style::Color;
use crate::utils::fmt::fmt_color;
use crate::utils::parser::parse_color;
// ext
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize, Serializer};
use tuirealm::tui::style::Color;
/// ### Theme
///
/// Theme contains all the colors lookup table for termscp
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)]
pub struct Theme {
// -- auth
#[serde(
@@ -217,9 +194,9 @@ fn deserialize_color<'de, D>(deserializer: D) -> Result<Color, D::Error>
where
D: Deserializer<'de>,
{
let s: &str = Deserialize::deserialize(deserializer)?;
let s: String = Deserialize::deserialize(deserializer)?;
// Parse color
match parse_color(s) {
match parse_color(&s) {
None => Err(DeError::custom("Invalid color")),
Some(color) => Ok(color),
}
@@ -236,10 +213,10 @@ where
#[cfg(test)]
mod test {
use super::*;
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn test_config_themes_default() {
let theme: Theme = Theme::default();

View File

@@ -2,35 +2,13 @@
//!
//! `builder` is the module which provides a builder for FileExplorer
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// Locals
use super::formatter::Formatter;
use super::{ExplorerOpts, FileExplorer, FileSorting, GroupDirs};
// Ext
use std::collections::VecDeque;
use super::formatter::Formatter;
use super::{ExplorerOpts, FileExplorer, FileSorting, GroupDirs};
/// Struct used to create a `FileExplorer`
pub struct FileExplorerBuilder {
explorer: Option<FileExplorer>,
@@ -87,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
}
@@ -99,10 +77,10 @@ impl FileExplorerBuilder {
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn test_fs_explorer_builder_new_default() {
let explorer: FileExplorer = FileExplorerBuilder::new().build();

View File

@@ -2,40 +2,21 @@
//!
//! `formatter` is the module which provides formatting utilities for `FileExplorer`
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// Locals
use crate::utils::fmt::{fmt_path_elide, fmt_pex, fmt_time};
use crate::utils::path::diff_paths;
// Ext
use bytesize::ByteSize;
use regex::Regex;
use remotefs::File;
use std::path::PathBuf;
use std::time::UNIX_EPOCH;
#[cfg(target_family = "unix")]
use users::{get_group_by_gid, get_user_by_uid};
// Ext
use bytesize::ByteSize;
use lazy_regex::{Lazy, Regex};
use remotefs::File;
use unicode_width::UnicodeWidthStr;
#[cfg(posix)]
use uzers::{get_group_by_gid, get_user_by_uid};
use crate::utils::fmt::{fmt_path_elide, fmt_pex, fmt_time};
use crate::utils::path::diff_paths;
use crate::utils::string::secure_substring;
// Types
// FmtCallback: Formatter, fsentry: &File, cur_str, prefix, length, extra
type FmtCallback = fn(&Formatter, &File, &str, &str, Option<&usize>, Option<&String>) -> String;
@@ -53,17 +34,14 @@ const FMT_KEY_SYMLINK: &str = "SYMLINK";
const FMT_KEY_USER: &str = "USER";
// Default
const FMT_DEFAULT_STX: &str = "{NAME} {PEX} {USER} {SIZE} {MTIME}";
// Regex
lazy_static! {
/**
* Regex matches:
* - group 0: KEY NAME
* - group 1?: LENGTH
* - group 2?: EXTRA
*/
static ref FMT_KEY_REGEX: Regex = Regex::new(r"\{(.*?)\}").ok().unwrap();
static ref FMT_ATTR_REGEX: Regex = Regex::new(r"(?:([A-Z]+))(:?([0-9]+))?(:?(.+))?").ok().unwrap();
}
/**
* Regex matches:
* - group 0: KEY NAME
* - group 1?: LENGTH
* - group 2?: EXTRA
*/
static FMT_KEY_REGEX: Lazy<Regex> = lazy_regex!(r"\{(.*?)\}");
static FMT_ATTR_REGEX: Lazy<Regex> = lazy_regex!(r"(?:([A-Z]+))(:?([0-9]+))?(:?(.+))?");
/// Call Chain block is a block in a chain of functions which are called in order to format the File.
/// A callChain is instantiated starting from the Formatter syntax and the regex, once the groups are found
@@ -233,7 +211,7 @@ impl Formatter {
_fmt_extra: Option<&String>,
) -> String {
// Get username
#[cfg(target_family = "unix")]
#[cfg(posix)]
let group: String = match fsentry.metadata().gid {
Some(gid) => match get_group_by_gid(gid) {
Some(user) => user.name().to_string_lossy().to_string(),
@@ -241,7 +219,7 @@ impl Formatter {
},
None => 0.to_string(),
};
#[cfg(target_os = "windows")]
#[cfg(win)]
let group: String = match fsentry.metadata().gid {
Some(gid) => gid.to_string(),
None => 0.to_string(),
@@ -303,15 +281,15 @@ impl Formatter {
true => file_len - 2,
false => file_len - 1,
};
let mut name: String = match name.len() >= file_len {
let mut name: String = match name.width() >= file_len {
false => name,
true => format!("{}", &name[0..last_idx]),
true => format!("{}", secure_substring(&name, 0, last_idx)),
};
if fsentry.is_dir() {
name.push('/');
}
// Add to cur str, prefix and the key value
format!("{}{}{:0width$}", cur_str, prefix, name, width = file_len)
format!("{cur_str}{prefix}{name:0file_len$}")
}
/// Format path
@@ -371,7 +349,7 @@ impl Formatter {
),
}
// Add to cur str, prefix and the key value
format!("{}{}{:10}", cur_str, prefix, pex)
format!("{cur_str}{prefix}{pex:10}")
}
/// Format file size
@@ -386,8 +364,16 @@ impl Formatter {
if fsentry.is_file() {
// Get byte size
let size: ByteSize = ByteSize(fsentry.metadata().size);
let mut fmt = size.display().si().to_string();
// pad with up to len 10
let pad = 10usize.saturating_sub(fmt.len());
for _ in 0..pad {
fmt.push(' ');
}
format!("{cur_str}{prefix}{fmt}")
// Add to cur str, prefix and the key value
format!("{}{}{:10}", cur_str, prefix, size.to_string())
//format!("{cur_str}{prefix}{size:10}", size = size.display().si())
} else if fsentry.metadata().symlink.is_some() {
let size = ByteSize(
fsentry
@@ -398,10 +384,17 @@ impl Formatter {
.to_string_lossy()
.len() as u64,
);
format!("{}{}{:10}", cur_str, prefix, size.to_string())
let mut fmt = size.display().si().to_string();
// pad with up to len 10
let pad = 10usize.saturating_sub(fmt.len());
for _ in 0..pad {
fmt.push(' ');
}
format!("{cur_str}{prefix}{fmt}")
} else {
// Add to cur str, prefix and the key value
format!("{}{} ", cur_str, prefix)
format!("{cur_str}{prefix} ")
}
}
@@ -421,7 +414,7 @@ impl Formatter {
};
// Replace `FMT_KEY_NAME` with name
match fsentry.metadata().symlink.as_deref() {
None => format!("{}{} ", cur_str, prefix),
None => format!("{cur_str}{prefix} "),
Some(p) => format!(
"{}{}-> {:0width$}",
cur_str,
@@ -442,7 +435,7 @@ impl Formatter {
_fmt_extra: Option<&String>,
) -> String {
// Get username
#[cfg(target_family = "unix")]
#[cfg(posix)]
let username: String = match fsentry.metadata().uid {
Some(uid) => match get_user_by_uid(uid) {
Some(user) => user.name().to_string_lossy().to_string(),
@@ -450,13 +443,13 @@ impl Formatter {
},
None => 0.to_string(),
};
#[cfg(target_os = "windows")]
#[cfg(win)]
let username: String = match fsentry.metadata().uid {
Some(uid) => uid.to_string(),
None => 0.to_string(),
};
// Add to cur str, prefix and the key value
format!("{}{}{:12}", cur_str, prefix, username)
format!("{cur_str}{prefix}{username:12}")
}
/// Fallback function in case the format key is unknown
@@ -470,7 +463,7 @@ impl Formatter {
_fmt_extra: Option<&String>,
) -> String {
// Add to cur str and prefix
format!("{}{}", cur_str, prefix)
format!("{cur_str}{prefix}")
}
// Static
@@ -511,10 +504,7 @@ impl Formatter {
};
// Match format length: group 3
let fmt_len: Option<usize> = match &regex_match.get(3) {
Some(len) => match len.as_str().parse::<usize>() {
Ok(len) => Some(len),
Err(_) => None,
},
Some(len) => len.as_str().parse::<usize>().ok(),
None => None,
};
// Match format extra: group 2 + 1
@@ -545,12 +535,13 @@ impl Formatter {
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
use std::time::SystemTime;
use pretty_assertions::assert_eq;
use remotefs::fs::{File, FileType, Metadata, UnixPex};
use std::path::PathBuf;
use std::time::SystemTime;
use super::*;
#[test]
fn test_fs_explorer_formatter_callchain() {
@@ -613,19 +604,19 @@ mod tests {
mode: Some(UnixPex::from(0o644)),
},
};
#[cfg(target_family = "unix")]
#[cfg(posix)]
assert_eq!(
formatter.fmt(&entry),
format!(
"bar.txt -rw-r--r-- root 8.2 KB {}",
"bar.txt -rw-r--r-- root 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
#[cfg(target_os = "windows")]
#[cfg(win)]
assert_eq!(
formatter.fmt(&entry),
format!(
"bar.txt -rw-r--r-- 0 8.2 KB {}",
"bar.txt -rw-r--r-- 0 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
@@ -644,19 +635,19 @@ mod tests {
mode: Some(UnixPex::from(0o644)),
},
};
#[cfg(target_family = "unix")]
#[cfg(posix)]
assert_eq!(
formatter.fmt(&entry),
format!(
"piroparoporoperoperupup… -rw-r--r-- root 8.2 KB {}",
"piroparoporoperoperupup… -rw-r--r-- root 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
#[cfg(target_os = "windows")]
#[cfg(win)]
assert_eq!(
formatter.fmt(&entry),
format!(
"piroparoporoperoperupup… -rw-r--r-- 0 8.2 KB {}",
"piroparoporoperoperupup… -rw-r--r-- 0 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
@@ -675,19 +666,19 @@ mod tests {
mode: None,
},
};
#[cfg(target_family = "unix")]
#[cfg(posix)]
assert_eq!(
formatter.fmt(&entry),
format!(
"bar.txt -????????? root 8.2 KB {}",
"bar.txt -????????? root 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
#[cfg(target_os = "windows")]
#[cfg(win)]
assert_eq!(
formatter.fmt(&entry),
format!(
"bar.txt -????????? 0 8.2 KB {}",
"bar.txt -????????? 0 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
@@ -706,19 +697,19 @@ mod tests {
mode: None,
},
};
#[cfg(target_family = "unix")]
#[cfg(posix)]
assert_eq!(
formatter.fmt(&entry),
format!(
"bar.txt -????????? 0 8.2 KB {}",
"bar.txt -????????? 0 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
#[cfg(target_os = "windows")]
#[cfg(win)]
assert_eq!(
formatter.fmt(&entry),
format!(
"bar.txt -????????? 0 8.2 KB {}",
"bar.txt -????????? 0 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
@@ -744,7 +735,7 @@ mod tests {
mode: Some(UnixPex::from(0o755)),
},
};
#[cfg(target_family = "unix")]
#[cfg(posix)]
assert_eq!(
formatter.fmt(&entry),
format!(
@@ -752,7 +743,7 @@ mod tests {
fmt_time(t, "%b %d %Y %H:%M")
)
);
#[cfg(target_os = "windows")]
#[cfg(win)]
assert_eq!(
formatter.fmt(&entry),
format!(
@@ -775,7 +766,7 @@ mod tests {
mode: None,
},
};
#[cfg(target_family = "unix")]
#[cfg(posix)]
assert_eq!(
formatter.fmt(&entry),
format!(
@@ -783,7 +774,7 @@ mod tests {
fmt_time(t, "%b %d %Y %H:%M")
)
);
#[cfg(target_os = "windows")]
#[cfg(win)]
assert_eq!(
formatter.fmt(&entry),
format!(
@@ -795,8 +786,9 @@ mod tests {
#[test]
fn test_fs_explorer_formatter_all_together_now() {
let formatter: Formatter =
Formatter::new("{NAME:16} {SYMLINK:12} {GROUP} {USER} {PEX} {SIZE} {ATIME:20:%a %b %d %Y %H:%M} {CTIME:20:%a %b %d %Y %H:%M} {MTIME:20:%a %b %d %Y %H:%M}");
let formatter: Formatter = Formatter::new(
"{NAME:16} {SYMLINK:12} {GROUP} {USER} {PEX} {SIZE} {ATIME:20:%a %b %d %Y %H:%M} {CTIME:20:%a %b %d %Y %H:%M} {MTIME:20:%a %b %d %Y %H:%M}",
);
// Directory (with symlink)
let t: SystemTime = SystemTime::now();
let entry = File {
@@ -813,12 +805,15 @@ mod tests {
mode: Some(UnixPex::from(0o755)),
},
};
assert_eq!(formatter.fmt(&entry), format!(
"projects -> project.info 0 0 lrwxr-xr-x 12 B {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
));
assert_eq!(
formatter.fmt(&entry),
format!(
"projects -> project.info 0 0 lrwxr-xr-x 12 B {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
)
);
// Directory without symlink
let entry = File {
path: PathBuf::from("/home/cvisintin/projects"),
@@ -834,12 +829,15 @@ mod tests {
mode: Some(UnixPex::from(0o755)),
},
};
assert_eq!(formatter.fmt(&entry), format!(
"projects/ 0 0 drwxr-xr-x {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
));
assert_eq!(
formatter.fmt(&entry),
format!(
"projects/ 0 0 drwxr-xr-x {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
)
);
// File with symlink
let entry = File {
path: PathBuf::from("/bar.txt"),
@@ -855,12 +853,15 @@ mod tests {
mode: Some(UnixPex::from(0o644)),
},
};
assert_eq!(formatter.fmt(&entry), format!(
"bar.txt -> project.info 0 0 lrw-r--r-- 12 B {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
));
assert_eq!(
formatter.fmt(&entry),
format!(
"bar.txt -> project.info 0 0 lrw-r--r-- 12 B {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
)
);
// File without symlink
let entry = File {
path: PathBuf::from("/bar.txt"),
@@ -876,16 +877,19 @@ mod tests {
mode: Some(UnixPex::from(0o644)),
},
};
assert_eq!(formatter.fmt(&entry), format!(
"bar.txt 0 0 -rw-r--r-- 8.2 KB {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
));
assert_eq!(
formatter.fmt(&entry),
format!(
"bar.txt 0 0 -rw-r--r-- 8.2 kB {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
)
);
}
#[test]
#[cfg(target_family = "unix")]
#[cfg(posix)]
fn should_fmt_path() {
let t: SystemTime = SystemTime::now();
let entry = File {
@@ -916,6 +920,113 @@ mod tests {
assert_eq!(formatter.fmt(&entry).as_str(), "File path: c/bar.txt");
}
#[test]
#[cfg(posix)]
fn should_fmt_utf8_path() {
let t: SystemTime = SystemTime::now();
let entry = File {
path: PathBuf::from("/tmp/a/b/c/россия"),
metadata: Metadata {
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::Symlink,
size: 8192,
symlink: Some(PathBuf::from("project.info")),
uid: None,
gid: None,
mode: Some(UnixPex::from(0o644)),
},
};
let formatter: Formatter = Formatter::new("File path: {PATH}");
assert_eq!(
formatter.fmt(&entry).as_str(),
"File path: /tmp/a/b/c/россия"
);
let formatter: Formatter = Formatter::new("File path: {PATH:8}");
assert_eq!(formatter.fmt(&entry).as_str(), "File path: /tmp/…/c/россия");
}
#[test]
fn should_fmt_short_ascii_name() {
let entry = File {
path: PathBuf::from("/tmp/foo.txt"),
metadata: Metadata {
accessed: None,
created: None,
modified: None,
file_type: FileType::File,
size: 8192,
symlink: None,
uid: None,
gid: None,
mode: None,
},
};
let formatter: Formatter = Formatter::new("{NAME:8}");
assert_eq!(formatter.fmt(&entry).as_str(), "foo.txt ");
}
#[test]
fn should_fmt_exceeding_length_ascii_name() {
let entry = File {
path: PathBuf::from("/tmp/christian-visintin.txt"),
metadata: Metadata {
accessed: None,
created: None,
modified: None,
file_type: FileType::File,
size: 8192,
symlink: None,
uid: None,
gid: None,
mode: None,
},
};
let formatter: Formatter = Formatter::new("{NAME:8}");
assert_eq!(formatter.fmt(&entry).as_str(), "christi…");
}
#[test]
fn should_fmt_short_utf8_name() {
let entry = File {
path: PathBuf::from("/tmp/россия"),
metadata: Metadata {
accessed: None,
created: None,
modified: None,
file_type: FileType::File,
size: 8192,
symlink: None,
uid: None,
gid: None,
mode: None,
},
};
let formatter: Formatter = Formatter::new("{NAME:8}");
assert_eq!(formatter.fmt(&entry).as_str(), "россия ");
}
#[test]
fn should_fmt_long_utf8_name() {
let entry = File {
path: PathBuf::from("/tmp/喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵喵"),
metadata: Metadata {
accessed: None,
created: None,
modified: None,
file_type: FileType::File,
size: 8192,
symlink: None,
uid: None,
gid: None,
mode: None,
},
};
let formatter: Formatter = Formatter::new("{NAME:8}");
assert_eq!(formatter.fmt(&entry).as_str(), "喵喵喵喵喵喵喵…");
}
/// Dummy formatter, just yelds an 'A' at the end of the current string
fn dummy_fmt(
_fmt: &Formatter,
@@ -925,6 +1036,6 @@ mod tests {
_fmt_len: Option<&usize>,
_fmt_extra: Option<&String>,
) -> String {
format!("{}{}A", cur_str, prefix)
format!("{cur_str}{prefix}A")
}
}

View File

@@ -2,62 +2,39 @@
//!
//! `explorer` is the module which provides an Helper in handling Directory status through
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// Mods
pub(crate) mod builder;
mod formatter;
// Locals
use std::cmp::Reverse;
use std::collections::{HashMap, VecDeque};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use formatter::Formatter;
// Ext
use remotefs::fs::File;
use std::cmp::Reverse;
use std::collections::VecDeque;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::string::ToString;
bitflags! {
/// ## ExplorerOpts
///
/// ExplorerOpts are bit options which provides different behaviours to `FileExplorer`
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub(crate) struct ExplorerOpts: u32 {
const SHOW_HIDDEN_FILES = 0b00000001;
}
}
/// FileSorting defines the criteria for sorting files
#[derive(Copy, Clone, PartialEq, std::fmt::Debug)]
#[derive(Copy, Clone, PartialEq, Eq, std::fmt::Debug)]
pub enum FileSorting {
Name,
ModifyTime,
CreationTime,
Size,
None,
}
/// GroupDirs defines how directories should be grouped in sorting files
#[derive(PartialEq, std::fmt::Debug)]
#[derive(PartialEq, Eq, std::fmt::Debug)]
pub enum GroupDirs {
First,
Last,
@@ -65,14 +42,26 @@ pub enum GroupDirs {
/// File explorer states
pub struct FileExplorer {
pub wrkdir: PathBuf, // Current directory
pub(crate) dirstack: VecDeque<PathBuf>, // Stack of visited directory (max 16)
pub(crate) stack_size: usize, // Directory stack size
pub(crate) file_sorting: FileSorting, // File sorting criteria
pub(crate) group_dirs: Option<GroupDirs>, // If Some, defines how to group directories
pub(crate) opts: ExplorerOpts, // Explorer options
pub(crate) fmt: Formatter, // File formatter
files: Vec<File>, // Files in directory
/// Current working directory
pub wrkdir: PathBuf,
/// Stack of visited directories
pub(crate) dirstack: VecDeque<PathBuf>,
/// Stack size
pub(crate) stack_size: usize,
/// Criteria to sort file
pub(crate) file_sorting: FileSorting,
/// defines how to group directories in the explorer
pub(crate) group_dirs: Option<GroupDirs>,
/// Explorer options
pub(crate) opts: ExplorerOpts,
/// Formatter for file entries
pub(crate) fmt: Formatter,
/// Is terminal open for this explorer?
terminal: bool,
/// Files in directory
files: Vec<File>,
/// files enqueued for transfer. Map between source and destination
transfer_queue: HashMap<PathBuf, PathBuf>, // transfer queue
}
impl Default for FileExplorer {
@@ -86,6 +75,8 @@ impl Default for FileExplorer {
opts: ExplorerOpts::empty(),
fmt: Formatter::default(),
files: Vec::new(),
terminal: false,
transfer_queue: HashMap::new(),
}
}
}
@@ -122,13 +113,6 @@ impl FileExplorer {
}
}
/*
/// Return amount of files
pub fn count(&self) -> usize {
self.files.len()
}
*/
/// Iterate over files
/// Filters are applied based on current options (e.g. hidden files not returned)
pub fn iter_files(&self) -> impl Iterator<Item = &File> + '_ {
@@ -169,6 +153,44 @@ impl FileExplorer {
filtered.get(idx).copied()
}
/// Enqueue a file for transfer
pub fn enqueue(&mut self, src: &Path, dst: &Path) {
self.transfer_queue
.insert(PathBuf::from(src), PathBuf::from(dst));
}
/// Enqueue all files for transfer
pub fn enqueue_all(&mut self, dst: &Path) {
let files: Vec<_> = self.iter_files().map(|f| f.path.clone()).collect();
for file in files {
self.enqueue(&file, dst);
}
}
/// Get enqueued files
pub fn enqueued(&self) -> &HashMap<PathBuf, PathBuf> {
&self.transfer_queue
}
/// Dequeue a file
pub fn dequeue(&mut self, src: &Path) {
self.transfer_queue.remove(src);
}
/// Clear transfer queue
pub fn clear_queue(&mut self) {
self.transfer_queue.clear();
}
/// Toggle terminal state
pub fn toggle_terminal(&mut self, terminal: bool) {
self.terminal = terminal;
}
pub fn terminal_open(&self) -> bool {
self.terminal
}
// Formatting
/// Format a file entry
@@ -209,6 +231,7 @@ impl FileExplorer {
FileSorting::CreationTime => self.sort_files_by_creation_time(),
FileSorting::ModifyTime => self.sort_files_by_mtime(),
FileSorting::Size => self.sort_files_by_size(),
FileSorting::None => {}
}
// Directories first (NOTE: MUST COME AFTER OTHER SORTING)
// Group directories if necessary
@@ -266,14 +289,19 @@ impl FileExplorer {
// Traits
impl ToString for FileSorting {
fn to_string(&self) -> String {
String::from(match self {
FileSorting::CreationTime => "by_creation_time",
FileSorting::ModifyTime => "by_mtime",
FileSorting::Name => "by_name",
FileSorting::Size => "by_size",
})
impl std::fmt::Display for FileSorting {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
FileSorting::CreationTime => "by_creation_time",
FileSorting::ModifyTime => "by_mtime",
FileSorting::Name => "by_name",
FileSorting::Size => "by_size",
FileSorting::None => "none",
}
)
}
}
@@ -290,12 +318,16 @@ impl FromStr for FileSorting {
}
}
impl ToString for GroupDirs {
fn to_string(&self) -> String {
String::from(match self {
GroupDirs::First => "first",
GroupDirs::Last => "last",
})
impl std::fmt::Display for GroupDirs {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
GroupDirs::First => "first",
GroupDirs::Last => "last",
}
)
}
}
@@ -313,13 +345,14 @@ impl FromStr for GroupDirs {
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::fmt::fmt_time;
use std::thread::sleep;
use std::time::{Duration, SystemTime};
use pretty_assertions::assert_eq;
use remotefs::fs::{File, FileType, Metadata, UnixPex};
use std::thread::sleep;
use std::time::{Duration, SystemTime};
use super::*;
use crate::utils::fmt::fmt_time;
#[test]
fn test_fs_explorer_new() {
@@ -337,12 +370,15 @@ mod tests {
#[test]
fn test_fs_explorer_stack() {
let mut explorer: FileExplorer = FileExplorer::default();
explorer.stack_size = 2;
let mut explorer = FileExplorer {
stack_size: 2,
dirstack: VecDeque::with_capacity(2),
..Default::default()
};
explorer.dirstack = VecDeque::with_capacity(2);
// Push dir
explorer.pushd(&Path::new("/tmp"));
explorer.pushd(&Path::new("/home/omar"));
explorer.pushd(Path::new("/tmp"));
explorer.pushd(Path::new("/home/omar"));
// Pop
assert_eq!(explorer.popd().unwrap(), PathBuf::from("/home/omar"));
assert_eq!(explorer.dirstack.len(), 1);
@@ -351,9 +387,9 @@ mod tests {
// Dirstack is empty now
assert!(explorer.popd().is_none());
// Exceed limit
explorer.pushd(&Path::new("/tmp"));
explorer.pushd(&Path::new("/home/omar"));
explorer.pushd(&Path::new("/dev"));
explorer.pushd(Path::new("/tmp"));
explorer.pushd(Path::new("/home/omar"));
explorer.pushd(Path::new("/dev"));
assert_eq!(explorer.dirstack.len(), 2);
assert_eq!(*explorer.dirstack.get(1).unwrap(), PathBuf::from("/dev"));
assert_eq!(
@@ -535,19 +571,19 @@ mod tests {
mode: Some(UnixPex::from(0o644)),
},
};
#[cfg(target_family = "unix")]
#[cfg(posix)]
assert_eq!(
explorer.fmt_file(&entry),
format!(
"bar.txt -rw-r--r-- root 8.2 KB {}",
"bar.txt -rw-r--r-- root 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
#[cfg(target_os = "windows")]
#[cfg(win)]
assert_eq!(
explorer.fmt_file(&entry),
format!(
"bar.txt -rw-r--r-- 0 8.2 KB {}",
"bar.txt -rw-r--r-- 0 8.2 kB {}",
fmt_time(t, "%b %d %Y %H:%M")
)
);
@@ -602,6 +638,26 @@ mod tests {
assert_eq!(explorer.files.len(), 3);
}
#[test]
fn test_should_enqueue_and_dequeue_files() {
let mut explorer: FileExplorer = FileExplorer::default();
// Create files (files are then sorted by name)
explorer.set_files(vec![
make_fs_entry("CONTRIBUTING.md", false),
make_fs_entry("docs", true),
make_fs_entry("src", true),
make_fs_entry("README.md", false),
]);
// Enqueue
explorer.enqueue(Path::new("CONTRIBUTING.md"), Path::new("CONTRIBUTING.md"));
explorer.enqueue(Path::new("docs"), Path::new("docs"));
// Dequeue
explorer.dequeue(Path::new("CONTRIBUTING.md"));
assert_eq!(explorer.enqueued().len(), 1);
explorer.dequeue(Path::new("docs"));
assert_eq!(explorer.enqueued().len(), 0);
}
fn make_fs_entry(name: &str, is_dir: bool) -> File {
let t: SystemTime = SystemTime::now();
let metadata = Metadata {

View File

@@ -1,233 +0,0 @@
//! ## builder
//!
//! Remotefs client builder
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use super::params::{AwsS3Params, GenericProtocolParams};
use super::{FileTransferProtocol, ProtocolParams};
use crate::system::config_client::ConfigClient;
use crate::system::sshkey_storage::SshKeyStorage;
use remotefs::RemoteFs;
use remotefs_aws_s3::AwsS3Fs;
use remotefs_ftp::FtpFs;
use remotefs_ssh::{ScpFs, SftpFs, SshOpts};
use std::path::PathBuf;
/// Remotefs builder
pub struct Builder;
impl Builder {
/// Build RemoteFs client from protocol and params.
///
/// if protocol and parameters are inconsistent, the function will panic.
pub fn build(
protocol: FileTransferProtocol,
params: ProtocolParams,
config_client: &ConfigClient,
) -> Box<dyn RemoteFs> {
match (protocol, params) {
(FileTransferProtocol::AwsS3, ProtocolParams::AwsS3(params)) => {
Box::new(Self::aws_s3_client(params))
}
(FileTransferProtocol::Ftp(secure), ProtocolParams::Generic(params)) => {
Box::new(Self::ftp_client(params, secure))
}
(FileTransferProtocol::Scp, ProtocolParams::Generic(params)) => {
Box::new(Self::scp_client(params, config_client))
}
(FileTransferProtocol::Sftp, ProtocolParams::Generic(params)) => {
Box::new(Self::sftp_client(params, config_client))
}
(protocol, params) => {
error!("Invalid params for protocol '{:?}'", protocol);
panic!(
"Invalid protocol '{:?}' with parameters of type {:?}",
protocol, params
)
}
}
}
/// Build aws s3 client from parameters
fn aws_s3_client(params: AwsS3Params) -> AwsS3Fs {
let mut client = AwsS3Fs::new(params.bucket_name, params.region);
if let Some(profile) = params.profile {
client = client.profile(profile);
}
if let Some(access_key) = params.access_key {
client = client.access_key(access_key);
}
if let Some(secret_access_key) = params.secret_access_key {
client = client.secret_access_key(secret_access_key);
}
if let Some(security_token) = params.security_token {
client = client.security_token(security_token);
}
if let Some(session_token) = params.session_token {
client = client.session_token(session_token);
}
client
}
/// Build ftp client from parameters
fn ftp_client(params: GenericProtocolParams, secure: bool) -> FtpFs {
let mut client = FtpFs::new(params.address, params.port).passive_mode();
if let Some(username) = params.username {
client = client.username(username);
}
if let Some(password) = params.password {
client = client.password(password);
}
if secure {
client = client.secure(true, true);
}
client
}
/// Build scp client
fn scp_client(params: GenericProtocolParams, config_client: &ConfigClient) -> ScpFs {
Self::build_ssh_opts(params, config_client).into()
}
/// Build sftp client
fn sftp_client(params: GenericProtocolParams, config_client: &ConfigClient) -> SftpFs {
Self::build_ssh_opts(params, config_client).into()
}
/// Build ssh options from generic protocol params and client configuration
fn build_ssh_opts(params: GenericProtocolParams, config_client: &ConfigClient) -> SshOpts {
let mut opts = SshOpts::new(params.address)
.key_storage(Box::new(Self::make_ssh_storage(config_client)))
.port(params.port);
if let Some(username) = params.username {
opts = opts.username(username);
}
if let Some(password) = params.password {
opts = opts.password(password);
}
if let Some(config_path) = config_client.get_ssh_config() {
opts = opts.config_file(PathBuf::from(config_path));
}
opts
}
/// Make ssh storage from `ConfigClient` if possible, empty otherwise (empty is implicit if degraded)
fn make_ssh_storage(config_client: &ConfigClient) -> SshKeyStorage {
SshKeyStorage::from(config_client)
}
}
#[cfg(test)]
mod test {
use super::*;
use std::path::{Path, PathBuf};
use tempfile::TempDir;
#[test]
fn should_build_aws_s3_fs() {
let params = ProtocolParams::AwsS3(
AwsS3Params::new("omar", "eu-west-1", Some("test"))
.access_key(Some("pippo"))
.secret_access_key(Some("pluto"))
.security_token(Some("omar"))
.session_token(Some("gerry-scotti")),
);
let config_client = get_config_client();
let _ = Builder::build(FileTransferProtocol::AwsS3, params, &config_client);
}
#[test]
fn should_build_ftp_fs() {
let params = ProtocolParams::Generic(
GenericProtocolParams::default()
.address("127.0.0.1")
.port(21)
.username(Some("omar"))
.password(Some("qwerty123")),
);
let config_client = get_config_client();
let _ = Builder::build(FileTransferProtocol::Ftp(true), params, &config_client);
}
#[test]
fn should_build_scp_fs() {
let params = ProtocolParams::Generic(
GenericProtocolParams::default()
.address("127.0.0.1")
.port(22)
.username(Some("omar"))
.password(Some("qwerty123")),
);
let config_client = get_config_client();
let _ = Builder::build(FileTransferProtocol::Scp, params, &config_client);
}
#[test]
fn should_build_sftp_fs() {
let params = ProtocolParams::Generic(
GenericProtocolParams::default()
.address("127.0.0.1")
.port(22)
.username(Some("omar"))
.password(Some("qwerty123")),
);
let config_client = get_config_client();
let _ = Builder::build(FileTransferProtocol::Sftp, params, &config_client);
}
#[test]
#[should_panic]
fn should_not_build_fs() {
let params = ProtocolParams::Generic(
GenericProtocolParams::default()
.address("127.0.0.1")
.port(22)
.username(Some("omar"))
.password(Some("qwerty123")),
);
let config_client = get_config_client();
let _ = Builder::build(FileTransferProtocol::AwsS3, params, &config_client);
}
fn get_config_client() -> ConfigClient {
let tmp_dir: TempDir = TempDir::new().ok().unwrap();
let (cfg_path, ssh_keys_path): (PathBuf, PathBuf) = get_paths(tmp_dir.path());
ConfigClient::new(cfg_path.as_path(), ssh_keys_path.as_path())
.ok()
.unwrap()
}
/// Get paths for configuration and keys directory
fn get_paths(dir: &Path) -> (PathBuf, PathBuf) {
let mut k: PathBuf = PathBuf::from(dir);
let mut c: PathBuf = k.clone();
k.push("ssh-keys/");
c.push("config.toml");
(c, k)
}
}

View File

@@ -0,0 +1,25 @@
use super::{HostBridgeParams, RemoteFsBuilder};
use crate::host::{HostBridge, Localhost, RemoteBridged};
use crate::system::config_client::ConfigClient;
pub struct HostBridgeBuilder;
impl HostBridgeBuilder {
/// Build Host Bridge from parms
///
/// if protocol and parameters are inconsistent, the function will return an error.
pub fn build(
params: HostBridgeParams,
config_client: &ConfigClient,
) -> Result<Box<dyn HostBridge>, String> {
match params {
HostBridgeParams::Localhost(path) => Localhost::new(path)
.map(|host| Box::new(host) as Box<dyn HostBridge>)
.map_err(|e| e.to_string()),
HostBridgeParams::Remote(protocol, params) => {
RemoteFsBuilder::build(protocol, params, config_client)
.map(|host| Box::new(RemoteBridged::from(host)) as Box<dyn HostBridge>)
}
}
}
}

View File

@@ -2,59 +2,48 @@
//!
//! `filetransfer` is the module which provides the file transfer protocols and remotefs builders
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
mod builder;
mod host_bridge_builder;
pub mod params;
mod remotefs_builder;
// -- export types
pub use builder::Builder;
pub use params::{FileTransferParams, ProtocolParams};
pub use host_bridge_builder::HostBridgeBuilder;
pub use params::{FileTransferParams, HostBridgeParams, ProtocolParams};
pub use remotefs_builder::RemoteFsBuilder;
/// This enum defines the different transfer protocol available in termscp
#[derive(PartialEq, Debug, Clone, Copy)]
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum FileTransferProtocol {
Sftp,
Scp,
Ftp(bool), // Bool is for secure (true => ftps)
AwsS3,
Ftp(bool), // Bool is for secure (true => ftps)
Kube,
Scp,
Sftp,
Smb,
WebDAV,
}
// Traits
impl std::string::ToString for FileTransferProtocol {
fn to_string(&self) -> String {
String::from(match self {
FileTransferProtocol::Ftp(secure) => match secure {
true => "FTPS",
false => "FTP",
},
FileTransferProtocol::Scp => "SCP",
FileTransferProtocol::Sftp => "SFTP",
FileTransferProtocol::AwsS3 => "S3",
})
impl std::fmt::Display for FileTransferProtocol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
FileTransferProtocol::AwsS3 => "S3",
FileTransferProtocol::Ftp(secure) => match secure {
true => "FTPS",
false => "FTP",
},
FileTransferProtocol::Kube => "KUBE",
FileTransferProtocol::Scp => "SCP",
FileTransferProtocol::Sftp => "SFTP",
FileTransferProtocol::Smb => "SMB",
FileTransferProtocol::WebDAV => "WEBDAV",
}
)
}
}
@@ -64,9 +53,12 @@ impl std::str::FromStr for FileTransferProtocol {
match s.to_ascii_uppercase().as_str() {
"FTP" => Ok(FileTransferProtocol::Ftp(false)),
"FTPS" => Ok(FileTransferProtocol::Ftp(true)),
"KUBE" => Ok(FileTransferProtocol::Kube),
"S3" => Ok(FileTransferProtocol::AwsS3),
"SCP" => Ok(FileTransferProtocol::Scp),
"SFTP" => Ok(FileTransferProtocol::Sftp),
"S3" => Ok(FileTransferProtocol::AwsS3),
"SMB" => Ok(FileTransferProtocol::Smb),
"WEBDAV" | "HTTP" | "HTTPS" => Ok(FileTransferProtocol::WebDAV),
_ => Err(s.to_string()),
}
}
@@ -77,12 +69,13 @@ impl std::str::FromStr for FileTransferProtocol {
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use std::str::FromStr;
use std::string::ToString;
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn test_filetransfer_mod_protocol() {
assert_eq!(
@@ -126,6 +119,22 @@ mod tests {
FileTransferProtocol::from_str("scp").ok().unwrap(),
FileTransferProtocol::Scp
);
assert_eq!(
FileTransferProtocol::from_str("kube").ok().unwrap(),
FileTransferProtocol::Kube
);
assert_eq!(
FileTransferProtocol::from_str("KUBE").ok().unwrap(),
FileTransferProtocol::Kube
);
assert_eq!(
FileTransferProtocol::from_str("SMB").ok().unwrap(),
FileTransferProtocol::Smb
);
assert_eq!(
FileTransferProtocol::from_str("smb").ok().unwrap(),
FileTransferProtocol::Smb
);
assert_eq!(
FileTransferProtocol::from_str("S3").ok().unwrap(),
FileTransferProtocol::AwsS3
@@ -145,8 +154,18 @@ mod tests {
FileTransferProtocol::Ftp(false).to_string(),
String::from("FTP")
);
assert_eq!(
FileTransferProtocol::WebDAV.to_string(),
String::from("WEBDAV")
);
assert_eq!(FileTransferProtocol::Scp.to_string(), String::from("SCP"));
assert_eq!(FileTransferProtocol::Sftp.to_string(), String::from("SFTP"));
assert_eq!(FileTransferProtocol::AwsS3.to_string(), String::from("S3"));
assert_eq!(FileTransferProtocol::Smb.to_string(), String::from("SMB"));
assert_eq!(
FileTransferProtocol::WebDAV.to_string(),
String::from("WEBDAV")
);
assert_eq!(FileTransferProtocol::Kube.to_string(), String::from("KUBE"));
}
}

View File

@@ -2,41 +2,63 @@
//!
//! file transfer parameters
/**
* MIT License
*
* termscp - Copyright (c) 2021 Christian Visintin
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use super::FileTransferProtocol;
mod aws_s3;
mod kube;
mod smb;
mod webdav;
use std::path::{Path, PathBuf};
/// ### FileTransferParams
///
pub use self::aws_s3::AwsS3Params;
pub use self::kube::KubeProtocolParams;
pub use self::smb::SmbParams;
pub use self::webdav::WebDAVProtocolParams;
use super::FileTransferProtocol;
/// Host bridge params
#[derive(Debug, Clone)]
pub enum HostBridgeParams {
/// Localhost with starting working directory
Localhost(PathBuf),
/// Remote host with protocol and file transfer params
Remote(FileTransferProtocol, ProtocolParams),
}
impl HostBridgeParams {
pub fn unwrap_protocol_params(&self) -> &ProtocolParams {
match self {
HostBridgeParams::Localhost(_) => panic!("Localhost has no protocol params"),
HostBridgeParams::Remote(_, params) => params,
}
}
/// Returns the host name for the bridge params
pub fn username(&self) -> Option<String> {
match self {
HostBridgeParams::Localhost(_) => Some(whoami::username()),
HostBridgeParams::Remote(_, params) => {
params.generic_params().and_then(|p| p.username.clone())
}
}
}
}
/// Holds connection parameters for file transfers
#[derive(Debug, Clone)]
pub struct FileTransferParams {
pub protocol: FileTransferProtocol,
pub params: ProtocolParams,
pub entry_directory: Option<PathBuf>,
pub remote_path: Option<PathBuf>,
pub local_path: Option<PathBuf>,
}
impl FileTransferParams {
/// Returns the remote path if set, otherwise returns the local path
pub fn username(&self) -> Option<String> {
self.params
.generic_params()
.and_then(|p| p.username.clone())
}
}
/// Container for protocol params
@@ -44,6 +66,46 @@ pub struct FileTransferParams {
pub enum ProtocolParams {
Generic(GenericProtocolParams),
AwsS3(AwsS3Params),
Kube(KubeProtocolParams),
Smb(SmbParams),
WebDAV(WebDAVProtocolParams),
}
impl ProtocolParams {
pub fn password_missing(&self) -> bool {
match self {
ProtocolParams::AwsS3(params) => params.password_missing(),
ProtocolParams::Generic(params) => params.password_missing(),
ProtocolParams::Kube(params) => params.password_missing(),
ProtocolParams::Smb(params) => params.password_missing(),
ProtocolParams::WebDAV(params) => params.password_missing(),
}
}
/// Set the secret to ft params for the default secret field for this protocol
pub fn set_default_secret(&mut self, secret: String) {
match self {
ProtocolParams::AwsS3(params) => params.set_default_secret(secret),
ProtocolParams::Generic(params) => params.set_default_secret(secret),
ProtocolParams::Kube(params) => params.set_default_secret(secret),
ProtocolParams::Smb(params) => params.set_default_secret(secret),
ProtocolParams::WebDAV(params) => params.set_default_secret(secret),
}
}
pub fn host_name(&self) -> String {
match self {
ProtocolParams::AwsS3(params) => params.bucket_name.clone(),
ProtocolParams::Generic(params) => params.address.clone(),
ProtocolParams::Kube(params) => params
.namespace
.as_ref()
.cloned()
.unwrap_or_else(|| String::from("default")),
ProtocolParams::Smb(params) => params.address.clone(),
ProtocolParams::WebDAV(params) => params.uri.clone(),
}
}
}
/// Protocol params used by most common protocols
@@ -55,33 +117,41 @@ pub struct GenericProtocolParams {
pub password: Option<String>,
}
/// Connection parameters for AWS S3 protocol
#[derive(Debug, Clone)]
pub struct AwsS3Params {
pub bucket_name: String,
pub region: String,
pub profile: Option<String>,
pub access_key: Option<String>,
pub secret_access_key: Option<String>,
pub security_token: Option<String>,
pub session_token: Option<String>,
}
impl FileTransferParams {
/// Instantiates a new `FileTransferParams`
pub fn new(protocol: FileTransferProtocol, params: ProtocolParams) -> Self {
Self {
protocol,
params,
entry_directory: None,
remote_path: None,
local_path: None,
}
}
/// Set entry directory
pub fn entry_directory<P: AsRef<Path>>(mut self, dir: Option<P>) -> Self {
self.entry_directory = dir.map(|x| x.as_ref().to_path_buf());
/// Set remote directory
pub fn remote_path<P: AsRef<Path>>(mut self, dir: Option<P>) -> Self {
self.remote_path = dir.map(|x| x.as_ref().to_path_buf());
self
}
/// Set local directory
pub fn local_path<P: AsRef<Path>>(mut self, dir: Option<P>) -> Self {
self.local_path = dir.map(|x| x.as_ref().to_path_buf());
self
}
/// Returns whether a password is supposed to be required for this protocol params.
/// The result true is returned ONLY if the supposed secret is MISSING!!!
#[cfg(test)]
pub fn password_missing(&self) -> bool {
self.params.password_missing()
}
/// Set the secret to ft params for the default secret field for this protocol
#[cfg(test)]
pub fn set_default_secret(&mut self, secret: String) {
self.params.set_default_secret(secret);
}
}
impl Default for FileTransferParams {
@@ -97,7 +167,6 @@ impl Default for ProtocolParams {
}
impl ProtocolParams {
#[cfg(test)]
/// Retrieve generic parameters from protocol params if any
pub fn generic_params(&self) -> Option<&GenericProtocolParams> {
match self {
@@ -106,6 +175,7 @@ impl ProtocolParams {
}
}
#[cfg(test)]
/// Get a mutable reference to the inner generic protocol params
pub fn mut_generic_params(&mut self) -> Option<&mut GenericProtocolParams> {
match self {
@@ -122,6 +192,33 @@ impl ProtocolParams {
_ => None,
}
}
#[cfg(test)]
/// Retrieve Kube params parameters if any
pub fn kube_params(&self) -> Option<&KubeProtocolParams> {
match self {
ProtocolParams::Kube(params) => Some(params),
_ => None,
}
}
#[cfg(test)]
/// Retrieve SMB parameters if any
pub fn smb_params(&self) -> Option<&SmbParams> {
match self {
ProtocolParams::Smb(params) => Some(params),
_ => None,
}
}
#[cfg(test)]
/// Retrieve WebDAV parameters if any
pub fn webdav_params(&self) -> Option<&WebDAVProtocolParams> {
match self {
ProtocolParams::WebDAV(params) => Some(params),
_ => None,
}
}
}
// -- Generic protocol params
@@ -161,69 +258,39 @@ impl GenericProtocolParams {
self.password = password.map(|x| x.as_ref().to_string());
self
}
}
// -- S3 params
impl AwsS3Params {
/// Instantiates a new `AwsS3Params` struct
pub fn new<S: AsRef<str>>(bucket: S, region: S, profile: Option<S>) -> Self {
Self {
bucket_name: bucket.as_ref().to_string(),
region: region.as_ref().to_string(),
profile: profile.map(|x| x.as_ref().to_string()),
access_key: None,
secret_access_key: None,
security_token: None,
session_token: None,
}
/// Returns whether a password is supposed to be required for this protocol params.
/// The result true is returned ONLY if the supposed secret is MISSING!!!
pub fn password_missing(&self) -> bool {
self.password.is_none()
}
/// Construct aws s3 params with provided access key
pub fn access_key<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
self.access_key = key.map(|x| x.as_ref().to_string());
self
}
/// Construct aws s3 params with provided secret_access_key
pub fn secret_access_key<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
self.secret_access_key = key.map(|x| x.as_ref().to_string());
self
}
/// Construct aws s3 params with provided security_token
pub fn security_token<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
self.security_token = key.map(|x| x.as_ref().to_string());
self
}
/// Construct aws s3 params with provided session_token
pub fn session_token<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
self.session_token = key.map(|x| x.as_ref().to_string());
self
/// Set password
pub fn set_default_secret(&mut self, secret: String) {
self.password = Some(secret);
}
}
#[cfg(test)]
mod test {
use super::*;
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn test_filetransfer_params() {
let params: FileTransferParams =
FileTransferParams::new(FileTransferProtocol::Scp, ProtocolParams::default())
.entry_directory(Some(&Path::new("/tmp")));
.remote_path(Some(&Path::new("/tmp")))
.local_path(Some(&Path::new("/usr")));
assert_eq!(
params.params.generic_params().unwrap().address.as_str(),
"localhost"
);
assert_eq!(params.protocol, FileTransferProtocol::Scp);
assert_eq!(
params.entry_directory.as_deref().unwrap(),
Path::new("/tmp")
);
assert_eq!(params.remote_path.as_deref().unwrap(), Path::new("/tmp"));
assert_eq!(params.local_path.as_deref().unwrap(), Path::new("/usr"));
}
#[test]
@@ -238,37 +305,10 @@ mod test {
assert!(params.password.is_none());
}
#[test]
fn should_init_aws_s3_params() {
let params: AwsS3Params = AwsS3Params::new("omar", "eu-west-1", Some("test"));
assert_eq!(params.bucket_name.as_str(), "omar");
assert_eq!(params.region.as_str(), "eu-west-1");
assert_eq!(params.profile.as_deref().unwrap(), "test");
assert!(params.access_key.is_none());
assert!(params.secret_access_key.is_none());
assert!(params.security_token.is_none());
assert!(params.session_token.is_none());
}
#[test]
fn should_init_aws_s3_params_with_optionals() {
let params: AwsS3Params = AwsS3Params::new("omar", "eu-west-1", Some("test"))
.access_key(Some("pippo"))
.secret_access_key(Some("pluto"))
.security_token(Some("omar"))
.session_token(Some("gerry-scotti"));
assert_eq!(params.bucket_name.as_str(), "omar");
assert_eq!(params.region.as_str(), "eu-west-1");
assert_eq!(params.profile.as_deref().unwrap(), "test");
assert_eq!(params.access_key.as_deref().unwrap(), "pippo");
assert_eq!(params.secret_access_key.as_deref().unwrap(), "pluto");
assert_eq!(params.security_token.as_deref().unwrap(), "omar");
assert_eq!(params.session_token.as_deref().unwrap(), "gerry-scotti");
}
#[test]
fn references() {
let mut params = ProtocolParams::AwsS3(AwsS3Params::new("omar", "eu-west-1", Some("test")));
let mut params =
ProtocolParams::AwsS3(AwsS3Params::new("omar", Some("eu-west-1"), Some("test")));
assert!(params.s3_params().is_some());
assert!(params.generic_params().is_none());
assert!(params.mut_generic_params().is_none());
@@ -277,4 +317,119 @@ mod test {
assert!(params.generic_params().is_some());
assert!(params.mut_generic_params().is_some());
}
#[test]
fn password_missing() {
assert!(
FileTransferParams::new(
FileTransferProtocol::Scp,
ProtocolParams::AwsS3(AwsS3Params::new("omar", Some("eu-west-1"), Some("test")))
)
.password_missing()
);
assert_eq!(
FileTransferParams::new(
FileTransferProtocol::Scp,
ProtocolParams::AwsS3(
AwsS3Params::new("omar", Some("eu-west-1"), Some("test"))
.secret_access_key(Some("test"))
)
)
.password_missing(),
false
);
assert_eq!(
FileTransferParams::new(
FileTransferProtocol::Scp,
ProtocolParams::AwsS3(
AwsS3Params::new("omar", Some("eu-west-1"), Some("test"))
.security_token(Some("test"))
)
)
.password_missing(),
false
);
assert!(
FileTransferParams::new(FileTransferProtocol::Scp, ProtocolParams::default())
.password_missing()
);
assert_eq!(
FileTransferParams::new(
FileTransferProtocol::Scp,
ProtocolParams::Generic(GenericProtocolParams::default().password(Some("Hello")))
)
.password_missing(),
false
);
}
#[test]
fn set_default_secret_aws_s3() {
let mut params = FileTransferParams::new(
FileTransferProtocol::Scp,
ProtocolParams::AwsS3(AwsS3Params::new("omar", Some("eu-west-1"), Some("test"))),
);
params.set_default_secret(String::from("secret"));
assert_eq!(
params
.params
.s3_params()
.unwrap()
.secret_access_key
.as_deref()
.unwrap(),
"secret"
);
}
#[test]
#[cfg(posix)]
fn set_default_secret_smb() {
let mut params = FileTransferParams::new(
FileTransferProtocol::Scp,
ProtocolParams::Smb(SmbParams::new("localhost", "temp")),
);
params.set_default_secret(String::from("secret"));
assert_eq!(
params
.params
.smb_params()
.unwrap()
.password
.as_deref()
.unwrap(),
"secret"
);
}
#[test]
fn set_default_secret_webdav() {
let mut params = FileTransferParams::new(
FileTransferProtocol::Scp,
ProtocolParams::WebDAV(WebDAVProtocolParams {
uri: "http://localhost".to_string(),
username: "user".to_string(),
password: "pass".to_string(),
}),
);
params.set_default_secret(String::from("secret"));
assert_eq!(params.params.webdav_params().unwrap().password, "secret");
}
#[test]
fn set_default_secret_generic() {
let mut params =
FileTransferParams::new(FileTransferProtocol::Scp, ProtocolParams::default());
params.set_default_secret(String::from("secret"));
assert_eq!(
params
.params
.generic_params()
.unwrap()
.password
.as_deref()
.unwrap(),
"secret"
);
}
}

View File

@@ -0,0 +1,121 @@
/// Connection parameters for AWS S3 protocol
#[derive(Debug, Clone)]
pub struct AwsS3Params {
pub bucket_name: String,
pub region: Option<String>,
pub endpoint: Option<String>,
pub profile: Option<String>,
pub access_key: Option<String>,
pub secret_access_key: Option<String>,
pub security_token: Option<String>,
pub session_token: Option<String>,
pub new_path_style: bool,
}
// -- S3 params
impl AwsS3Params {
/// Instantiates a new `AwsS3Params` struct
pub fn new<S: AsRef<str>>(bucket: S, region: Option<S>, profile: Option<S>) -> Self {
Self {
bucket_name: bucket.as_ref().to_string(),
region: region.map(|x| x.as_ref().to_string()),
profile: profile.map(|x| x.as_ref().to_string()),
endpoint: None,
access_key: None,
secret_access_key: None,
security_token: None,
session_token: None,
new_path_style: false,
}
}
/// Construct aws s3 params with specified endpoint
pub fn endpoint<S: AsRef<str>>(mut self, endpoint: Option<S>) -> Self {
self.endpoint = endpoint.map(|x| x.as_ref().to_string());
self
}
/// Construct aws s3 params with provided access key
pub fn access_key<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
self.access_key = key.map(|x| x.as_ref().to_string());
self
}
/// Construct aws s3 params with provided secret_access_key
pub fn secret_access_key<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
self.secret_access_key = key.map(|x| x.as_ref().to_string());
self
}
/// Construct aws s3 params with provided security_token
pub fn security_token<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
self.security_token = key.map(|x| x.as_ref().to_string());
self
}
/// Construct aws s3 params with provided session_token
pub fn session_token<S: AsRef<str>>(mut self, key: Option<S>) -> Self {
self.session_token = key.map(|x| x.as_ref().to_string());
self
}
/// Specify new path style when constructing aws s3 params
pub fn new_path_style(mut self, new_path_style: bool) -> Self {
self.new_path_style = new_path_style;
self
}
/// Returns whether a password is supposed to be required for this protocol params.
/// The result true is returned ONLY if the supposed secret is MISSING!!!
pub fn password_missing(&self) -> bool {
self.secret_access_key.is_none() && self.security_token.is_none()
}
/// Set password
pub fn set_default_secret(&mut self, secret: String) {
self.secret_access_key = Some(secret);
}
}
#[cfg(test)]
mod test {
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn should_init_aws_s3_params() {
let params: AwsS3Params = AwsS3Params::new("omar", Some("eu-west-1"), Some("test"));
assert_eq!(params.bucket_name.as_str(), "omar");
assert_eq!(params.region.as_deref().unwrap(), "eu-west-1");
assert_eq!(params.profile.as_deref().unwrap(), "test");
assert!(params.endpoint.is_none());
assert!(params.access_key.is_none());
assert!(params.secret_access_key.is_none());
assert!(params.security_token.is_none());
assert!(params.session_token.is_none());
assert_eq!(params.new_path_style, false);
}
#[test]
fn should_init_aws_s3_params_with_optionals() {
let params: AwsS3Params = AwsS3Params::new("omar", Some("eu-west-1"), Some("test"))
.endpoint(Some("http://omar.it"))
.access_key(Some("pippo"))
.secret_access_key(Some("pluto"))
.security_token(Some("omar"))
.session_token(Some("gerry-scotti"))
.new_path_style(true);
assert_eq!(params.bucket_name.as_str(), "omar");
assert_eq!(params.region.as_deref().unwrap(), "eu-west-1");
assert_eq!(params.profile.as_deref().unwrap(), "test");
assert_eq!(params.endpoint.as_deref().unwrap(), "http://omar.it");
assert_eq!(params.access_key.as_deref().unwrap(), "pippo");
assert_eq!(params.secret_access_key.as_deref().unwrap(), "pluto");
assert_eq!(params.security_token.as_deref().unwrap(), "omar");
assert_eq!(params.session_token.as_deref().unwrap(), "gerry-scotti");
assert_eq!(params.new_path_style, true);
}
}

Some files were not shown because too many files have changed in this diff Show More