Compare commits

...

94 Commits

Author SHA1 Message Date
Zack 50e0f625bc v10.0.7 2024-05-31 14:32:59 -07:00
Zack 94af2374c3 Merge branch 'main' of github.com:schollz/croc 2024-05-31 14:32:03 -07:00
Zack a4322faa25 ui: add newlines to skipping messages 2024-05-31 14:31:46 -07:00
Zack 23dce2aa3e
Merge pull request #724 from schollz:schollz/issue723
fix: receiver needs to exit without initializing files if no files being transfered
2024-05-31 11:45:51 -07:00
Zack 88002b322d fix: receiver needs to exit without initializing files if no files being transfered 2024-05-31 11:44:56 -07:00
Zack 9246408278 for valid filename tests 2024-05-30 15:21:51 -07:00
Zack fbf1eeedce v10.0.6 2024-05-28 16:24:29 -07:00
Zack e4c9f2d9fb
Merge pull request #721 from schollz:schollz/issue720
show hash progress on large files
2024-05-28 16:21:45 -07:00
Zack c0c3370d9b add highway hash 2024-05-28 16:19:38 -07:00
Zack f6bd13fa06 show hash progress on large files 2024-05-28 16:08:31 -07:00
Zack Scholl f83616e9bd readme: remove coverage badge 2024-05-26 11:37:03 -07:00
Zack Scholl 23f385ab2f readme: update badge for CI 2024-05-26 11:35:54 -07:00
Zack Scholl 78feb393de fix println warnings 2024-05-26 11:33:21 -07:00
Zack 69fc3cee47 v10.0.5 2024-05-26 07:58:08 -07:00
Zack a5da77cf49
Merge pull request #717 from schollz:schollz/issue716
new: add flag `--classic` with warning for passing shared secret on single-user systems
2024-05-26 07:55:31 -07:00
Zack f66e17dd46 add the checks for the classic insecure mode 2024-05-26 07:54:37 -07:00
Zack 63c9201938 new: add flag with warning for passing shared secret on single-user systems 2024-05-26 07:52:12 -07:00
Zack ca7a5979cc need environmental variable on all unix systems 2024-05-26 07:20:48 -07:00
Zack fc457557e0 v10.0.4 2024-05-25 09:02:34 -07:00
Zack f044f4dd86
Merge pull request #713 from schollz:schollz/issue712
escape filenames that have invisible characters while allowing other languages
2024-05-25 09:00:36 -07:00
Zack a2e71c7e1a escape filenames that have invisible characters while allowing other languages
Fixes #712
2024-05-25 08:59:38 -07:00
Zack dff34fa7fc fix comment 2024-05-24 19:44:28 -07:00
Zack Scholl 08103bb7bb v10.0.3 2024-05-24 18:04:29 -07:00
Zack Scholl 4091ef0496 fix: remove hash extra 2024-05-24 18:03:51 -07:00
Zack 381f8369a3 update bug report 2024-05-23 09:49:18 -07:00
Zack a95d67e31c v10.0.2 2024-05-23 09:47:15 -07:00
Zack b0920bbe70
Merge pull request #708 from schollz/fix10
fix message passing for initial secure layer
2024-05-23 09:46:40 -07:00
Zack ed55c746c2 fix message passing for initial secure layer 2024-05-23 09:44:34 -07:00
Zack 8e10eac5c5 fix 2024-05-23 09:34:17 -07:00
Zack 43f1c53538 v10.0.1 2024-05-23 08:35:56 -07:00
Zack 3acac5d53b
Merge pull request #707 from schollz:schollz/issue706
ux: improve the environmental variable messaging for sending/receiving
2024-05-23 08:34:52 -07:00
Zack 66f0d1264a improve the ux around sending 2024-05-23 08:33:00 -07:00
Zack ee713c5146 improve ux around receiving 2024-05-23 08:27:52 -07:00
Zack 6181903c83 go.mod v9 -> v10 2024-05-23 06:25:53 -07:00
Zack 7acd2def69 version bump for breaking change 2024-05-23 06:15:03 -07:00
Zack eb0909033e reduce description lengths 2024-05-22 10:10:55 -07:00
Zack f6d862eac0 bump version 2024-05-20 12:08:57 -07:00
Zack 5a6005f1eb bump version 2024-05-20 12:08:45 -07:00
Zack f6633cbac9
Merge pull request #702 from schollz:schollz/issue599
chore: improve efficiency and remove extraneous reads
2024-05-20 10:39:49 -07:00
Zack d8ef7cda20 chore: improve efficiency and remove extraneous reads 2024-05-20 10:39:22 -07:00
Zack 7622e636e4 fix: refactor gathering ips 2024-05-20 10:16:37 -07:00
Zack bb018fd725 fix: address shared secret before creatgin 2024-05-20 10:16:02 -07:00
Zack 863dabb93a
Merge pull request #701 from schollz/issue598
fix: shared secret should be read from environmental variable
2024-05-20 09:53:39 -07:00
Zack 6f5f16aa1c
Merge pull request #700 from schollz/issue597
fix: establish encryption layer before transfering ip information
2024-05-20 09:53:31 -07:00
Zack 0f1ca436cd
Merge pull request #699 from schollz/issue596
fix: use more secure shared secret as room name
2024-05-20 09:53:17 -07:00
Zack 4929635eb8
Merge pull request #698 from schollz/schollz/issue594
fix: prompt for overwriting when unzipping
2024-05-20 09:53:09 -07:00
Zack 3f12f75fae
Merge pull request #697 from schollz/issue593
fix: client quits when discovering dangerous paths
2024-05-20 09:52:58 -07:00
Zack e255d472a6 fix: shared secret should be read from environmental variable 2024-05-20 09:46:38 -07:00
Zack 2ffd4daeaf fix: establish encryption layer before transfering ip information 2024-05-20 09:37:42 -07:00
Zack accb310337 ignore 2024-05-20 09:11:08 -07:00
Zack 2b4c088100 fix: use more secure shared secret as room name 2024-05-20 09:08:10 -07:00
Zack a591833dbf fix: filter escape sequences in filenames 2024-05-20 08:38:36 -07:00
Zack b3668a6f5c fix: prompt for overwriting when unzipping 2024-05-20 08:31:47 -07:00
Zack b05c3c8c42 fix: client quits when discovering dangerous paths 2024-05-20 08:23:21 -07:00
Zack 13bc190f8b ignore big file 2024-05-20 08:08:38 -07:00
Zack 1b90484bb8 chore: update dependencies 2024-05-20 06:08:20 -07:00
Zack Scholl 05359d6976 update deps 2024-05-12 16:15:52 +00:00
Zack Scholl cc4d74c490 Merge branch 'main' of github.com:schollz/croc 2024-04-06 16:45:03 +00:00
Zack d81116382f bump version to 9.6.15 2024-04-06 09:44:08 -07:00
Zack Scholl 94cc880568 Merge branch 'main' of github.com:schollz/croc 2024-04-06 16:44:02 +00:00
Zack 24b907f4bb chore: update deps 2024-04-06 09:43:27 -07:00
Zack Scholl 8166b2dbed Merge branch 'main' of github.com:schollz/croc 2024-04-05 21:39:02 +00:00
Zack 14187f6f30
Merge pull request #688 from schollz/dependabot/go_modules/golang.org/x/crypto-0.22.0
Bump golang.org/x/crypto from 0.21.0 to 0.22.0
2024-04-05 14:38:56 -07:00
dependabot[bot] 90682d3ebd
Bump golang.org/x/crypto from 0.21.0 to 0.22.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.21.0 to 0.22.0.
- [Commits](https://github.com/golang/crypto/compare/v0.21.0...v0.22.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-05 08:21:46 +00:00
Zack Scholl f4057aa28b Merge branch 'main' of github.com:schollz/croc 2024-04-04 18:31:02 +00:00
Zack 3c2548aa69
Merge pull request #687 from schollz/dependabot/go_modules/golang.org/x/net-0.23.0
Bump golang.org/x/net from 0.22.0 to 0.23.0
2024-04-04 11:30:06 -07:00
dependabot[bot] 7bab9c3cb5
Bump golang.org/x/net from 0.22.0 to 0.23.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to 0.23.0.
- [Commits](https://github.com/golang/net/compare/v0.22.0...v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-04 08:06:47 +00:00
Zack Scholl 355628f895 Merge branch 'main' of github.com:schollz/croc 2024-04-01 19:29:03 +00:00
Zack eaffc6dcac
Merge pull request #686 from a1lu/readonly
Avoid to create config dir if not required
2024-04-01 12:28:36 -07:00
a1lu 4baec420c8 Aovoid to create config dir if not required
If `--remember` is not set, the config dir should not created.
2024-04-01 13:39:04 +02:00
a1lu cd89e8043f Introduce var doRemember in cli receive function 2024-04-01 13:15:50 +02:00
Zack Scholl 1324ff8897 Merge branch 'main' of github.com:schollz/croc 2024-03-31 19:11:02 +00:00
Zack 8bc7a62b9e
Merge pull request #683 from a1lu/patch-1
Support spaces in 4 word codes
2024-03-31 12:10:32 -07:00
Zack Scholl 0c49ac3f02 Merge branch 'main' of github.com:schollz/croc 2024-03-31 19:09:02 +00:00
Zack 8b4ab4c86c
Merge pull request #685 from a1lu/config_files
Gracefully handle non existend receive config file
2024-03-31 12:08:50 -07:00
Zack Scholl f8f69e3157 Merge branch 'main' of github.com:schollz/croc 2024-03-31 19:08:03 +00:00
Zack 4e75e131c4
Merge pull request #682 from vihu/rg/update-error-message
Update error message to be more verbose
2024-03-31 12:07:45 -07:00
a1lu e599e56415 Gracefully handle non existend receive config file
If croc shall not remember the config, it should not exit if the config
file could not be opened. This is similar to the handling of the send
config.
2024-03-31 00:08:12 +01:00
a1lu 956598c427 Check $HOME as last 2024-03-30 23:24:52 +01:00
a1lu 618ae1e5d0
Support spaces in 4 word codes
Since the code was extended by the 4 digit block, the patch from https://github.com/schollz/croc/pull/198 did not work anymore.
2024-03-30 22:58:16 +01:00
Zack Scholl 7763a971f2 Merge branch 'main' of github.com:schollz/croc 2024-03-30 18:49:02 +00:00
Zack d2b7c80369 chore: update dependencies 2024-03-30 11:48:03 -07:00
Rahul Garg 241176d8a4
Update error message to be more verbose
Summary
----
This changes the error message (when connecting to an unavailble
channel) like so:

before:

```
$ croc 6764-jimmy-hilton-inside
securing channel...2024/03/28 17:16:25 room not ready
```

after:

```
$ ./croc 6764-jimmy-hilton-inside
securing channel...2024/03/28 17:16:12 room (secure channel) not ready, maybe peer disconnected
```
2024-03-28 17:16:01 -06:00
Zack Scholl 719f9b62c9 Merge branch 'main' of github.com:schollz/croc 2024-03-11 22:51:03 +00:00
Zack Scholl 03e6dcd220 Merge branch 'main' of github.com:schollz/croc 2024-03-11 22:50:02 +00:00
Zack Scholl 6b930c365b Merge branch 'main' of github.com:schollz/croc 2024-03-11 22:49:03 +00:00
Zack Scholl 6f2771e7b5 Merge branch 'main' of github.com:schollz/croc 2024-03-11 13:46:03 +00:00
Zack Scholl 945ac74690 Merge branch 'main' of github.com:schollz/croc 2024-03-05 04:57:05 +00:00
Zack Scholl 28ef8e99ac Merge branch 'main' of github.com:schollz/croc 2024-02-22 22:41:05 +00:00
Zack Scholl ab2cb477a8 Merge branch 'main' of github.com:schollz/croc 2024-02-22 22:40:05 +00:00
Zack Scholl c7f0228786 Merge branch 'main' of github.com:schollz/croc 2024-02-22 22:35:05 +00:00
Zack Scholl de9c54e57a Merge branch 'main' of github.com:schollz/croc 2024-02-20 15:59:03 +00:00
Zack Scholl 064f84ccd3 Merge branch 'main' of github.com:schollz/croc 2024-02-19 15:55:51 +00:00
Zack ce91e3b420
Merge pull request #660 from qk-santi/ports-and-transfers
define ports by amount, not individually
2024-02-12 08:08:01 -07:00
18 changed files with 620 additions and 194 deletions

View File

@ -2,7 +2,6 @@
name: Bug report name: Bug report
about: Create a report to help us improve about: Create a report to help us improve
title: '' title: ''
labels: bug
assignees: '' assignees: ''
--- ---
@ -12,15 +11,10 @@ assignees: ''
<!-- Please try to download latest, https://github.com/schollz/croc/releases/latest of croc before reporting a bug! --> <!-- Please try to download latest, https://github.com/schollz/croc/releases/latest of croc before reporting a bug! -->
## Describe the bug ## Describe the bug
<-- A clear and concise description of what the bug is. -->
## To Reproduce ## To Reproduce
Steps to reproduce the behavior: Steps to reproduce the behavior:
<-- 1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error -->
1. 1.
2. 2.
@ -28,14 +22,10 @@ Steps to reproduce the behavior:
4. 4.
## Expected behaviour ## Expected behaviour
<-- A clear and concise description of what you expected to happen. -->
## Version ## Version
<-- Check "croc -v" and report it -->
## Additional context ## Additional context
<-- Add any other context about the problem here. -->

2
.gitignore vendored
View File

@ -9,3 +9,5 @@ croc-stdin*
.idea/ .idea/
.vscode/ .vscode/
src/utils/bigfile.test
test1/

View File

@ -10,12 +10,12 @@ install: true
script: script:
- env GO111MODULE=on go build -v - env GO111MODULE=on go build -v
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/compress - env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/compress
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/croc - env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/croc
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/crypt - env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/crypt
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/tcp - env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/tcp
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/utils - env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/utils
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/comm - env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/comm
branches: branches:
except: except:

View File

@ -4,10 +4,9 @@
src="https://user-images.githubusercontent.com/6550035/46709024-9b23ad00-cbf6-11e8-9fb2-ca8b20b7dbec.jpg" src="https://user-images.githubusercontent.com/6550035/46709024-9b23ad00-cbf6-11e8-9fb2-ca8b20b7dbec.jpg"
width="408px" border="0" alt="croc"> width="408px" border="0" alt="croc">
<br> <br>
<a href="https://github.com/schollz/croc/releases/latest"><img src="https://img.shields.io/badge/version-v9.6.14-brightgreen.svg?style=flat-square" alt="Version"></a> <a href="https://github.com/schollz/croc/releases/latest"><img src="https://img.shields.io/badge/version-v10.0.7-brightgreen.svg?style=flat-square" alt="Version"></a>
<a href="https://coveralls.io/github/schollz/croc"><img src="https://img.shields.io/badge/coverage-81%25-green.svg?style=flat-square" alt="Coverage"></a> <a href="https://github.com/schollz/croc/actions/workflows/ci.yml"><img
<a href="https://travis-ci.org/schollz/croc"><img src="https://github.com/schollz/croc/actions/workflows/ci.yml/badge.svg" alt="Build
src="https://img.shields.io/travis/schollz/croc.svg?style=flat-square" alt="Build
Status"></a> Status"></a>
<p align="center">This project is supported by <a href="https://github.com/sponsors/schollz">Github sponsors</a>.</p> <p align="center">This project is supported by <a href="https://github.com/sponsors/schollz">Github sponsors</a>.</p>
@ -108,7 +107,7 @@ pkg install croc
Or, you can [install Go](https://golang.org/dl/) and build from source (requires Go 1.17+): Or, you can [install Go](https://golang.org/dl/) and build from source (requires Go 1.17+):
``` ```
go install github.com/schollz/croc/v9@latest go install github.com/schollz/croc/v10@latest
``` ```
On Android there is a 3rd party F-Droid app [available to download](https://f-droid.org/en/packages/com.github.howeyc.crocgui/). On Android there is a 3rd party F-Droid app [available to download](https://f-droid.org/en/packages/com.github.howeyc.crocgui/).

20
go.mod
View File

@ -1,4 +1,4 @@
module github.com/schollz/croc/v9 module github.com/schollz/croc/v10
go 1.20 go 1.20
@ -12,17 +12,19 @@ require (
github.com/schollz/logger v1.2.0 github.com/schollz/logger v1.2.0
github.com/schollz/mnemonicode v1.0.2-0.20190421205639-63fa713ece0d github.com/schollz/mnemonicode v1.0.2-0.20190421205639-63fa713ece0d
github.com/schollz/pake/v3 v3.0.5 github.com/schollz/pake/v3 v3.0.5
github.com/schollz/peerdiscovery v1.7.2 github.com/schollz/peerdiscovery v1.7.3
github.com/schollz/progressbar/v3 v3.14.2 github.com/schollz/progressbar/v3 v3.14.3
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.21.0 golang.org/x/crypto v0.23.0
golang.org/x/net v0.22.0 golang.org/x/net v0.25.0
golang.org/x/time v0.5.0 golang.org/x/time v0.5.0
) )
require github.com/minio/highwayhash v1.0.2
require ( require (
github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
@ -32,9 +34,9 @@ require (
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406 // indirect github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406 // indirect
github.com/twmb/murmur3 v1.1.8 // indirect github.com/twmb/murmur3 v1.1.8 // indirect
golang.org/x/sys v0.18.0 // indirect golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.18.0 // indirect golang.org/x/term v0.20.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.15.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

40
go.sum
View File

@ -11,8 +11,8 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -29,6 +29,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI= github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI=
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg= github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -48,10 +50,10 @@ github.com/schollz/mnemonicode v1.0.2-0.20190421205639-63fa713ece0d h1:3zCjdgCJb
github.com/schollz/mnemonicode v1.0.2-0.20190421205639-63fa713ece0d/go.mod h1:cl4UAOhUV0mkdjMj/QYaUZbZZdF8BnOqoz8rHMzwboY= github.com/schollz/mnemonicode v1.0.2-0.20190421205639-63fa713ece0d/go.mod h1:cl4UAOhUV0mkdjMj/QYaUZbZZdF8BnOqoz8rHMzwboY=
github.com/schollz/pake/v3 v3.0.5 h1:MnZVdI987lkjln9BSx/zUb724TZISa2jbO+dPj6BvgQ= github.com/schollz/pake/v3 v3.0.5 h1:MnZVdI987lkjln9BSx/zUb724TZISa2jbO+dPj6BvgQ=
github.com/schollz/pake/v3 v3.0.5/go.mod h1:OGbG6htRwSKo6V8R5tg61ufpFmZM1b/PrrSp6g2ZLLc= github.com/schollz/pake/v3 v3.0.5/go.mod h1:OGbG6htRwSKo6V8R5tg61ufpFmZM1b/PrrSp6g2ZLLc=
github.com/schollz/peerdiscovery v1.7.2 h1:H5IAGcJIRkh2aIl00HnaqpUBJsZTDhWqmpLR0RaR21Y= github.com/schollz/peerdiscovery v1.7.3 h1:/pt1G0rZ80fSPoI/FgGC5P7MxpkRXD6u0pe6PJbYcIE=
github.com/schollz/peerdiscovery v1.7.2/go.mod h1:NtkZS9cL2C/zSUC9dwxX4lyyZjwbjD5to3DgHh8uYtc= github.com/schollz/peerdiscovery v1.7.3/go.mod h1:mVlPNJ5DWbMi52VzpXxGbqXKdFANx3qw0Jsp3EQMCrE=
github.com/schollz/progressbar/v3 v3.14.2 h1:EducH6uNLIWsr560zSV1KrTeUb/wZGAHqyMFIEa99ks= github.com/schollz/progressbar/v3 v3.14.3 h1:oOuWW19ka12wxYU1XblR4n16wF/2Y1dBLMarMo6p4xU=
github.com/schollz/progressbar/v3 v3.14.2/go.mod h1:aQAZQnhF4JGFtRJiw/eobaXpsqpVQAftEQ+hLGXaRc4= github.com/schollz/progressbar/v3 v3.14.3/go.mod h1:aT3UQ7yGm+2ZjeXPqsjTenwL3ddUiuZ0kfQ/2tHlyNI=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
@ -70,9 +72,9 @@ github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -80,12 +82,13 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -95,25 +98,24 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

View File

@ -7,7 +7,7 @@ package main
import ( import (
"log" "log"
"github.com/schollz/croc/v9/src/cli" "github.com/schollz/croc/v10/src/cli"
) )
func main() { func main() {

View File

@ -15,11 +15,11 @@ import (
"github.com/chzyer/readline" "github.com/chzyer/readline"
"github.com/schollz/cli/v2" "github.com/schollz/cli/v2"
"github.com/schollz/croc/v9/src/comm" "github.com/schollz/croc/v10/src/comm"
"github.com/schollz/croc/v9/src/croc" "github.com/schollz/croc/v10/src/croc"
"github.com/schollz/croc/v9/src/models" "github.com/schollz/croc/v10/src/models"
"github.com/schollz/croc/v9/src/tcp" "github.com/schollz/croc/v10/src/tcp"
"github.com/schollz/croc/v9/src/utils" "github.com/schollz/croc/v10/src/utils"
log "github.com/schollz/logger" log "github.com/schollz/logger"
"github.com/schollz/mnemonicode" "github.com/schollz/mnemonicode"
"github.com/schollz/pake/v3" "github.com/schollz/pake/v3"
@ -36,7 +36,7 @@ func Run() (err error) {
app := cli.NewApp() app := cli.NewApp()
app.Name = "croc" app.Name = "croc"
if Version == "" { if Version == "" {
Version = "v9.6.14" Version = "v10.0.7"
} }
app.Version = Version app.Version = Version
app.Compiled = time.Now() app.Compiled = time.Now()
@ -92,6 +92,7 @@ func Run() (err error) {
} }
app.Flags = []cli.Flag{ app.Flags = []cli.Flag{
&cli.BoolFlag{Name: "internal-dns", Usage: "use a built-in DNS stub resolver rather than the host operating system"}, &cli.BoolFlag{Name: "internal-dns", Usage: "use a built-in DNS stub resolver rather than the host operating system"},
&cli.BoolFlag{Name: "classic", Usage: "toggle between the classic mode (insecure due to local attack vector) and new mode (secure)"},
&cli.BoolFlag{Name: "remember", Usage: "save these settings to reuse next time"}, &cli.BoolFlag{Name: "remember", Usage: "save these settings to reuse next time"},
&cli.BoolFlag{Name: "debug", Usage: "toggle debug mode"}, &cli.BoolFlag{Name: "debug", Usage: "toggle debug mode"},
&cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"}, &cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
@ -125,6 +126,61 @@ func Run() (err error) {
return true return true
} }
// check if "classic" is set
classicFile := getClassicConfigFile(true)
classicInsecureMode := utils.Exists(classicFile)
if c.Bool("classic") {
if classicInsecureMode {
// classic mode not enabled
fmt.Print(`Classic mode is currently ENABLED.
Disabling this mode will prevent the shared secret from being visible
on the host's process list when passed via the command line. On a
multi-user system, this will help ensure that other local users cannot
access the shared secret and receive the files instead of the intended
recipient.
Do you wish to continue to DISABLE the classic mode? (Y/n) `)
choice := strings.ToLower(utils.GetInput(""))
if choice == "y" || choice == "yes" {
os.Remove(classicFile)
fmt.Print("\nClassic mode DISABLED.\n\n")
fmt.Print(`To send and receive, export the CROC_SECRET variable with the code phrase:
Send: CROC_SECRET=*** croc send file.txt
Receive: CROC_SECRET=*** croc` + "\n\n")
} else {
fmt.Print("\nClassic mode ENABLED.\n")
}
} else {
// enable classic mode
// touch the file
fmt.Print(`Classic mode is currently DISABLED.
Please note that enabling this mode will make the shared secret visible
on the host's process list when passed via the command line. On a
multi-user system, this could allow other local users to access the
shared secret and receive the files instead of the intended recipient.
Do you wish to continue to enable the classic mode? (Y/n) `)
choice := strings.ToLower(utils.GetInput(""))
if choice == "y" || choice == "yes" {
fmt.Print("\nClassic mode ENABLED.\n\n")
os.WriteFile(classicFile, []byte("enabled"), 0o644)
fmt.Print(`To send and receive, use the code phrase:
Send: croc send --code *** file.txt
Receive: croc ***` + "\n\n")
} else {
fmt.Print("\nClassic mode DISABLED.\n")
}
}
os.Exit(0)
}
// if trying to send but forgot send, let the user know // if trying to send but forgot send, let the user know
if c.Args().Present() && allStringsAreFiles(c.Args().Slice()) { if c.Args().Present() && allStringsAreFiles(c.Args().Slice()) {
fnames := []string{} fnames := []string{}
@ -138,6 +194,7 @@ func Run() (err error) {
return send(c) return send(c)
} }
} }
return receive(c) return receive(c)
} }
@ -153,8 +210,8 @@ func setDebugLevel(c *cli.Context) {
} }
} }
func getConfigFile() string { func getSendConfigFile(requireValidPath bool) string {
configFile, err := utils.GetConfigDir() configFile, err := utils.GetConfigDir(requireValidPath)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
return "" return ""
@ -162,6 +219,24 @@ func getConfigFile() string {
return path.Join(configFile, "send.json") return path.Join(configFile, "send.json")
} }
func getClassicConfigFile(requireValidPath bool) string {
configFile, err := utils.GetConfigDir(requireValidPath)
if err != nil {
log.Error(err)
return ""
}
return path.Join(configFile, "classic_enabled")
}
func getReceiveConfigFile(requireValidPath bool) (string, error) {
configFile, err := utils.GetConfigDir(requireValidPath)
if err != nil {
log.Error(err)
return "", err
}
return path.Join(configFile, "receive.json"), nil
}
func determinePass(c *cli.Context) (pass string) { func determinePass(c *cli.Context) (pass string) {
pass = c.String("pass") pass = c.String("pass")
b, err := os.ReadFile(pass) b, err := os.ReadFile(pass)
@ -219,7 +294,7 @@ func send(c *cli.Context) (err error) {
} else if crocOptions.RelayAddress6 != models.DEFAULT_RELAY6 { } else if crocOptions.RelayAddress6 != models.DEFAULT_RELAY6 {
crocOptions.RelayAddress = "" crocOptions.RelayAddress = ""
} }
b, errOpen := os.ReadFile(getConfigFile()) b, errOpen := os.ReadFile(getSendConfigFile(false))
if errOpen == nil && !c.Bool("remember") { if errOpen == nil && !c.Bool("remember") {
var rememberedOptions croc.Options var rememberedOptions croc.Options
err = json.Unmarshal(b, &rememberedOptions) err = json.Unmarshal(b, &rememberedOptions)
@ -295,6 +370,32 @@ func send(c *cli.Context) (err error) {
return errors.New("must specify file: croc send [filename(s) or folder]") return errors.New("must specify file: croc send [filename(s) or folder]")
} }
classicInsecureMode := utils.Exists(getClassicConfigFile(true))
if !classicInsecureMode {
// if operating system is UNIX, then use environmental variable to set the code
if (!(runtime.GOOS == "windows") && c.IsSet("code")) || os.Getenv("CROC_SECRET") != "" {
crocOptions.SharedSecret = os.Getenv("CROC_SECRET")
if crocOptions.SharedSecret == "" {
fmt.Printf(`On UNIX systems, to send with a custom code phrase,
you need to set the environmental variable CROC_SECRET:
export CROC_SECRET="****"
croc send file.txt
Or you can have the code phrase automaticlaly generated:
croc send file.txt
Or you can go back to the classic croc behavior by enabling classic mode:
croc --classic
`)
os.Exit(0)
}
}
}
if len(crocOptions.SharedSecret) == 0 { if len(crocOptions.SharedSecret) == 0 {
// generate code phrase // generate code phrase
crocOptions.SharedSecret = utils.GetRandomName() crocOptions.SharedSecret = utils.GetRandomName()
@ -355,7 +456,7 @@ func makeTempFileWithString(s string) (fnames []string, err error) {
func saveConfig(c *cli.Context, crocOptions croc.Options) { func saveConfig(c *cli.Context, crocOptions croc.Options) {
if c.Bool("remember") { if c.Bool("remember") {
configFile := getConfigFile() configFile := getSendConfigFile(true)
log.Debug("saving config file") log.Debug("saving config file")
var bConfig []byte var bConfig []byte
// if the code wasn't set, don't save it // if the code wasn't set, don't save it
@ -435,6 +536,8 @@ func receive(c *cli.Context) (err error) {
case 1: case 1:
crocOptions.SharedSecret = c.Args().First() crocOptions.SharedSecret = c.Args().First()
case 3: case 3:
fallthrough
case 4:
var phrase []string var phrase []string
phrase = append(phrase, c.Args().First()) phrase = append(phrase, c.Args().First())
phrase = append(phrase, c.Args().Tail()...) phrase = append(phrase, c.Args().Tail()...)
@ -443,14 +546,14 @@ func receive(c *cli.Context) (err error) {
// load options here // load options here
setDebugLevel(c) setDebugLevel(c)
configFile, err := utils.GetConfigDir()
if err != nil { doRemember := c.Bool("remember")
log.Error(err) configFile, err := getReceiveConfigFile(doRemember)
if err != nil && doRemember {
return return
} }
configFile = path.Join(configFile, "receive.json")
b, errOpen := os.ReadFile(configFile) b, errOpen := os.ReadFile(configFile)
if errOpen == nil && !c.Bool("remember") { if errOpen == nil && !doRemember {
var rememberedOptions croc.Options var rememberedOptions croc.Options
err = json.Unmarshal(b, &rememberedOptions) err = json.Unmarshal(b, &rememberedOptions)
if err != nil { if err != nil {
@ -484,6 +587,32 @@ func receive(c *cli.Context) (err error) {
} }
} }
classicInsecureMode := utils.Exists(getClassicConfigFile(true))
if crocOptions.SharedSecret == "" && os.Getenv("CROC_SECRET") != "" {
crocOptions.SharedSecret = os.Getenv("CROC_SECRET")
} else if !(runtime.GOOS == "windows") && crocOptions.SharedSecret != "" && !classicInsecureMode {
crocOptions.SharedSecret = os.Getenv("CROC_SECRET")
if crocOptions.SharedSecret == "" {
fmt.Printf(`On UNIX systems, to receive with croc you either need
to set a code phrase using your environmental variables:
export CROC_SECRET="****"
croc
Or you can specify the code phrase when you run croc without
declaring the secret on the command line:
croc
Enter receive code: ****
Or you can go back to the classic croc behavior by enabling classic mode:
croc --classic
`)
os.Exit(0)
}
}
if crocOptions.SharedSecret == "" { if crocOptions.SharedSecret == "" {
l, err := readline.NewEx(&readline.Config{ l, err := readline.NewEx(&readline.Config{
Prompt: "Enter receive code: ", Prompt: "Enter receive code: ",
@ -509,7 +638,7 @@ func receive(c *cli.Context) (err error) {
} }
// save the config // save the config
if c.Bool("remember") { if doRemember {
log.Debug("saving config file") log.Debug("saving config file")
var bConfig []byte var bConfig []byte
bConfig, err = json.MarshalIndent(crocOptions, "", " ") bConfig, err = json.MarshalIndent(crocOptions, "", " ")

View File

@ -11,7 +11,7 @@ import (
"time" "time"
"github.com/magisterquis/connectproxy" "github.com/magisterquis/connectproxy"
"github.com/schollz/croc/v9/src/utils" "github.com/schollz/croc/v10/src/utils"
log "github.com/schollz/logger" log "github.com/schollz/logger"
"golang.org/x/net/proxy" "golang.org/x/net/proxy"
) )

View File

@ -3,7 +3,9 @@ package croc
import ( import (
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"crypto/sha256"
"encoding/binary" "encoding/binary"
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -26,13 +28,13 @@ import (
"github.com/schollz/peerdiscovery" "github.com/schollz/peerdiscovery"
"github.com/schollz/progressbar/v3" "github.com/schollz/progressbar/v3"
"github.com/schollz/croc/v9/src/comm" "github.com/schollz/croc/v10/src/comm"
"github.com/schollz/croc/v9/src/compress" "github.com/schollz/croc/v10/src/compress"
"github.com/schollz/croc/v9/src/crypt" "github.com/schollz/croc/v10/src/crypt"
"github.com/schollz/croc/v9/src/message" "github.com/schollz/croc/v10/src/message"
"github.com/schollz/croc/v9/src/models" "github.com/schollz/croc/v10/src/models"
"github.com/schollz/croc/v9/src/tcp" "github.com/schollz/croc/v10/src/tcp"
"github.com/schollz/croc/v9/src/utils" "github.com/schollz/croc/v10/src/utils"
) )
var ( var (
@ -57,6 +59,7 @@ func Debug(debug bool) {
type Options struct { type Options struct {
IsSender bool IsSender bool
SharedSecret string SharedSecret string
RoomName string
Debug bool Debug bool
RelayAddress string RelayAddress string
RelayAddress6 string RelayAddress6 string
@ -81,6 +84,11 @@ type Options struct {
GitIgnore bool GitIgnore bool
} }
type SimpleMessage struct {
Bytes []byte
Kind string
}
// Client holds the state of the croc transfer // Client holds the state of the croc transfer
type Client struct { type Client struct {
Options Options Options Options
@ -182,12 +190,15 @@ func New(ops Options) (c *Client, err error) {
// setup basic info // setup basic info
c.Options = ops c.Options = ops
Debug(c.Options.Debug) Debug(c.Options.Debug)
log.Debugf("options: %+v", c.Options)
if len(c.Options.SharedSecret) < 6 { if len(c.Options.SharedSecret) < 6 {
err = fmt.Errorf("code is too short") err = fmt.Errorf("code is too short")
return return
} }
// Create a hash of part of the shared secret to use as the room name
hashExtra := "croc"
roomNameBytes := sha256.Sum256([]byte(c.Options.SharedSecret[:4] + hashExtra))
c.Options.RoomName = hex.EncodeToString(roomNameBytes[:])
c.conn = make([]*comm.Comm, 16) c.conn = make([]*comm.Comm, 16)
@ -495,7 +506,7 @@ func (c *Client) sendCollectFiles(filesInfo []FileInfo) (err error) {
c.Options.HashAlgorithm = "xxhash" c.Options.HashAlgorithm = "xxhash"
} }
c.FilesToTransfer[i].Hash, err = utils.HashFile(fullPath, c.Options.HashAlgorithm) c.FilesToTransfer[i].Hash, err = utils.HashFile(fullPath, c.Options.HashAlgorithm, fileInfo.Size > 1e7)
log.Debugf("hashed %s to %x using %s", fullPath, c.FilesToTransfer[i].Hash, c.Options.HashAlgorithm) log.Debugf("hashed %s to %x using %s", fullPath, c.FilesToTransfer[i].Hash, c.Options.HashAlgorithm)
totalFilesSize += fileInfo.Size totalFilesSize += fileInfo.Size
if err != nil { if err != nil {
@ -582,7 +593,7 @@ func (c *Client) transferOverLocalRelay(errchan chan<- error) {
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
log.Debug("establishing connection") log.Debug("establishing connection")
var banner string var banner string
conn, banner, ipaddr, err := tcp.ConnectToTCPServer("127.0.0.1:"+c.Options.RelayPorts[0], c.Options.RelayPassword, c.Options.SharedSecret[:3]) conn, banner, ipaddr, err := tcp.ConnectToTCPServer("127.0.0.1:"+c.Options.RelayPorts[0], c.Options.RelayPassword, c.Options.RoomName)
log.Debugf("banner: %s", banner) log.Debugf("banner: %s", banner)
if err != nil { if err != nil {
err = fmt.Errorf("could not connect to 127.0.0.1:%s: %w", c.Options.RelayPorts[0], err) err = fmt.Errorf("could not connect to 127.0.0.1:%s: %w", c.Options.RelayPorts[0], err)
@ -670,7 +681,7 @@ func (c *Client) Send(filesInfo []FileInfo, emptyFoldersToTransfer []FileInfo, t
log.Debugf("got host '%v' and port '%v'", host, port) log.Debugf("got host '%v' and port '%v'", host, port)
address = net.JoinHostPort(host, port) address = net.JoinHostPort(host, port)
log.Debugf("trying connection to %s", address) log.Debugf("trying connection to %s", address)
conn, banner, ipaddr, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.SharedSecret[:3], durations[i]) conn, banner, ipaddr, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.RoomName, durations[i])
if err == nil { if err == nil {
c.Options.RelayAddress = address c.Options.RelayAddress = address
break break
@ -688,13 +699,34 @@ func (c *Client) Send(filesInfo []FileInfo, emptyFoldersToTransfer []FileInfo, t
} }
log.Debugf("banner: %s", banner) log.Debugf("banner: %s", banner)
log.Debugf("connection established: %+v", conn) log.Debugf("connection established: %+v", conn)
var kB []byte
B, _ := pake.InitCurve([]byte(c.Options.SharedSecret[5:]), 1, c.Options.Curve)
for { for {
log.Debug("waiting for bytes") var dataMessage SimpleMessage
log.Trace("waiting for bytes")
data, errConn := conn.Receive() data, errConn := conn.Receive()
if errConn != nil { if errConn != nil {
log.Debugf("[%+v] had error: %s", conn, errConn.Error()) log.Tracef("[%+v] had error: %s", conn, errConn.Error())
}
json.Unmarshal(data, &dataMessage)
log.Tracef("data: %+v '%s'", data, data)
log.Tracef("dataMessage: %s", dataMessage)
log.Tracef("kB: %x", kB)
// if kB not null, then use it to decrypt
if kB != nil {
var decryptErr error
var dataDecrypt []byte
dataDecrypt, decryptErr = crypt.Decrypt(data, kB)
if decryptErr != nil {
log.Tracef("error decrypting: %v: '%s'", decryptErr, data)
} else {
// copy dataDecrypt to data
data = dataDecrypt
log.Tracef("decrypted: %s", data)
}
} }
if bytes.Equal(data, ipRequest) { if bytes.Equal(data, ipRequest) {
log.Tracef("got ipRequest")
// recipient wants to try to connect to local ips // recipient wants to try to connect to local ips
var ips []string var ips []string
// only get local ips if the local is enabled // only get local ips if the local is enabled
@ -702,22 +734,48 @@ func (c *Client) Send(filesInfo []FileInfo, emptyFoldersToTransfer []FileInfo, t
// get list of local ips // get list of local ips
ips, err = utils.GetLocalIPs() ips, err = utils.GetLocalIPs()
if err != nil { if err != nil {
log.Debugf("error getting local ips: %v", err) log.Tracef("error getting local ips: %v", err)
} }
// prepend the port that is being listened to // prepend the port that is being listened to
ips = append([]string{c.Options.RelayPorts[0]}, ips...) ips = append([]string{c.Options.RelayPorts[0]}, ips...)
} }
bips, _ := json.Marshal(ips) log.Tracef("sending ips: %+v", ips)
bips, errIps := json.Marshal(ips)
if errIps != nil {
log.Tracef("error marshalling ips: %v", errIps)
}
bips, errIps = crypt.Encrypt(bips, kB)
if errIps != nil {
log.Tracef("error encrypting ips: %v", errIps)
}
if err = conn.Send(bips); err != nil { if err = conn.Send(bips); err != nil {
log.Errorf("error sending: %v", err) log.Errorf("error sending: %v", err)
} }
} else if dataMessage.Kind == "pake1" {
log.Trace("got pake1")
var pakeError error
pakeError = B.Update(dataMessage.Bytes)
if pakeError == nil {
kB, pakeError = B.SessionKey()
if pakeError == nil {
log.Tracef("dataMessage kB: %x", kB)
dataMessage.Bytes = B.Bytes()
dataMessage.Kind = "pake2"
data, _ = json.Marshal(dataMessage)
if pakeError = conn.Send(data); err != nil {
log.Errorf("dataMessage error sending: %v", err)
}
}
}
} else if bytes.Equal(data, handshakeRequest) { } else if bytes.Equal(data, handshakeRequest) {
log.Trace("got handshake")
break break
} else if bytes.Equal(data, []byte{1}) { } else if bytes.Equal(data, []byte{1}) {
log.Debug("got ping") log.Trace("got ping")
continue continue
} else { } else {
log.Debugf("[%+v] got weird bytes: %+v", conn, data) log.Tracef("[%+v] got weird bytes: %+v", conn, data)
// throttle the reading // throttle the reading
errchan <- fmt.Errorf("gracefully refusing using the public relay") errchan <- fmt.Errorf("gracefully refusing using the public relay")
return return
@ -867,7 +925,7 @@ func (c *Client) Receive() (err error) {
log.Debugf("got host '%v' and port '%v'", host, port) log.Debugf("got host '%v' and port '%v'", host, port)
address = net.JoinHostPort(host, port) address = net.JoinHostPort(host, port)
log.Debugf("trying connection to %s", address) log.Debugf("trying connection to %s", address)
c.conn[0], banner, c.ExternalIP, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.SharedSecret[:3], durations[i]) c.conn[0], banner, c.ExternalIP, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.RoomName, durations[i])
if err == nil { if err == nil {
c.Options.RelayAddress = address c.Options.RelayAddress = address
break break
@ -888,20 +946,68 @@ func (c *Client) Receive() (err error) {
if c.Options.TestFlag || (!usingLocal && !c.Options.DisableLocal && !isIPset) { if c.Options.TestFlag || (!usingLocal && !c.Options.DisableLocal && !isIPset) {
// ask the sender for their local ips and port // ask the sender for their local ips and port
// and try to connect to them // and try to connect to them
log.Debug("sending ips?")
var data []byte
if err = c.conn[0].Send(ipRequest); err != nil {
log.Errorf("ips send error: %v", err)
}
data, err = c.conn[0].Receive()
if err != nil {
return
}
log.Debugf("ips data: %s", data)
var ips []string var ips []string
if err = json.Unmarshal(data, &ips); err != nil { err = func() (err error) {
log.Debugf("ips unmarshal error: %v", err) var A *pake.Pake
} var data []byte
A, err = pake.InitCurve([]byte(c.Options.SharedSecret[5:]), 0, c.Options.Curve)
if err != nil {
return err
}
dataMessage := SimpleMessage{
Bytes: A.Bytes(),
Kind: "pake1",
}
data, _ = json.Marshal(dataMessage)
if err = c.conn[0].Send(data); err != nil {
log.Errorf("dataMessage send error: %v", err)
return
}
data, err = c.conn[0].Receive()
if err != nil {
return
}
err = json.Unmarshal(data, &dataMessage)
if err != nil || dataMessage.Kind != "pake2" {
log.Debugf("data: %s", data)
return fmt.Errorf("dataMessage %s pake failed", ipRequest)
}
err = A.Update(dataMessage.Bytes)
if err != nil {
return
}
var kA []byte
kA, err = A.SessionKey()
if err != nil {
return
}
log.Debugf("dataMessage kA: %x", kA)
// secure ipRequest
data, err = crypt.Encrypt([]byte(ipRequest), kA)
if err != nil {
return
}
log.Debug("sending ips?")
if err = c.conn[0].Send(data); err != nil {
log.Errorf("ips send error: %v", err)
}
data, err = c.conn[0].Receive()
if err != nil {
return
}
data, err = crypt.Decrypt(data, kA)
if err != nil {
return
}
log.Debugf("ips data: %s", data)
if err = json.Unmarshal(data, &ips); err != nil {
log.Debugf("ips unmarshal error: %v", err)
}
return
}()
if len(ips) > 1 { if len(ips) > 1 {
port := ips[0] port := ips[0]
ips = ips[1:] ips = ips[1:]
@ -925,7 +1031,7 @@ func (c *Client) Receive() (err error) {
} }
serverTry := net.JoinHostPort(ip, port) serverTry := net.JoinHostPort(ip, port)
conn, banner2, externalIP, errConn := tcp.ConnectToTCPServer(serverTry, c.Options.RelayPassword, c.Options.SharedSecret[:3], 500*time.Millisecond) conn, banner2, externalIP, errConn := tcp.ConnectToTCPServer(serverTry, c.Options.RelayPassword, c.Options.RoomName, 500*time.Millisecond)
if errConn != nil { if errConn != nil {
log.Debug(errConn) log.Debug(errConn)
log.Debugf("could not connect to " + serverTry) log.Debugf("could not connect to " + serverTry)
@ -958,7 +1064,7 @@ func (c *Client) Receive() (err error) {
err = c.transfer() err = c.transfer()
if err == nil { if err == nil {
if c.numberOfTransferredFiles+len(c.EmptyFoldersToTransfer) == 0 { if c.numberOfTransferredFiles+len(c.EmptyFoldersToTransfer) == 0 {
fmt.Fprintf(os.Stderr, "\rNo files transferred.") fmt.Fprintf(os.Stderr, "\rNo files transferred.\n")
} }
} }
return return
@ -997,6 +1103,7 @@ func (c *Client) transfer() (err error) {
} }
done, err = c.processMessage(data) done, err = c.processMessage(data)
if err != nil { if err != nil {
log.Debugf("data: %s", data)
log.Debugf("got error processing: %v", err) log.Debugf("got error processing: %v", err)
break break
} }
@ -1052,7 +1159,7 @@ func (c *Client) transfer() (err error) {
} }
if err != nil && strings.Contains(err.Error(), "unexpected end of JSON input") { if err != nil && strings.Contains(err.Error(), "unexpected end of JSON input") {
log.Debugf("error: %s", err.Error()) log.Debugf("error: %s", err.Error())
err = fmt.Errorf("room not ready") err = fmt.Errorf("room (secure channel) not ready, maybe peer disconnected")
} }
return return
} }
@ -1092,6 +1199,21 @@ func (c *Client) processMessageFileInfo(m message.Message) (done bool, err error
c.EmptyFoldersToTransfer = senderInfo.EmptyFoldersToTransfer c.EmptyFoldersToTransfer = senderInfo.EmptyFoldersToTransfer
c.TotalNumberFolders = senderInfo.TotalNumberFolders c.TotalNumberFolders = senderInfo.TotalNumberFolders
c.FilesToTransfer = senderInfo.FilesToTransfer c.FilesToTransfer = senderInfo.FilesToTransfer
for i, fi := range c.FilesToTransfer {
// Issues #593 - sanitize the sender paths and prevent ".." from being used
c.FilesToTransfer[i].FolderRemote = filepath.Clean(fi.FolderRemote)
if strings.Contains(c.FilesToTransfer[i].FolderRemote, "..") {
return true, fmt.Errorf("invalid path detected: '%s'", fi.FolderRemote)
}
// Issues #593 - disallow specific folders like .ssh
if strings.Contains(c.FilesToTransfer[i].FolderRemote, ".ssh") {
return true, fmt.Errorf("invalid path detected: '%s'", fi.FolderRemote)
}
// Issue #595 - disallow filenames with invisible characters
if !utils.ValidFileName(path.Join(c.FilesToTransfer[i].FolderRemote, fi.Name)) {
return true, fmt.Errorf("invalid filename detected: '%s'", fi.Name)
}
}
c.TotalNumberOfContents = 0 c.TotalNumberOfContents = 0
if c.FilesToTransfer != nil { if c.FilesToTransfer != nil {
c.TotalNumberOfContents += len(c.FilesToTransfer) c.TotalNumberOfContents += len(c.FilesToTransfer)
@ -1275,7 +1397,7 @@ func (c *Client) processMessagePake(m message.Message) (err error) {
c.conn[j+1], _, _, err = tcp.ConnectToTCPServer( c.conn[j+1], _, _, err = tcp.ConnectToTCPServer(
server, server,
c.Options.RelayPassword, c.Options.RelayPassword,
fmt.Sprintf("%s-%d", utils.SHA256(c.Options.SharedSecret[:5])[:6], j), fmt.Sprintf("%s-%d", c.Options.RoomName, j),
) )
if err != nil { if err != nil {
panic(err) panic(err)
@ -1516,6 +1638,7 @@ func (c *Client) recipientGetFileReady(finished bool) (err error) {
} }
c.SuccessfulTransfer = true c.SuccessfulTransfer = true
c.FilesHasFinished[c.FilesToTransferCurrentNum] = struct{}{} c.FilesHasFinished[c.FilesToTransferCurrentNum] = struct{}{}
return
} }
err = c.recipientInitializeFile() err = c.recipientInitializeFile()
@ -1588,6 +1711,9 @@ func (c *Client) createEmptyFileAndFinish(fileInfo FileInfo, i int) (err error)
} else { } else {
description = " " + description description = " " + description
} }
if len(description) > 20 {
description = description[:17] + "..."
}
c.bar = progressbar.NewOptions64(1, c.bar = progressbar.NewOptions64(1,
progressbar.OptionOnCompletion(func() { progressbar.OptionOnCompletion(func() {
c.fmtPrintUpdate() c.fmtPrintUpdate()
@ -1655,7 +1781,7 @@ func (c *Client) updateIfRecipientHasFileInfo() (err error) {
} }
choice := strings.ToLower(utils.GetInput(prompt)) choice := strings.ToLower(utils.GetInput(prompt))
if choice != "y" && choice != "yes" { if choice != "y" && choice != "yes" {
fmt.Fprintf(os.Stderr, "skipping '%s'", path.Join(fileInfo.FolderRemote, fileInfo.Name)) fmt.Fprintf(os.Stderr, "Skipping '%s'\n", path.Join(fileInfo.FolderRemote, fileInfo.Name))
continue continue
} }
} }
@ -1764,6 +1890,9 @@ func (c *Client) setBar() {
} else if !c.Options.IsSender { } else if !c.Options.IsSender {
description = " " + description description = " " + description
} }
if len(description) > 20 {
description = description[:17] + "..."
}
c.bar = progressbar.NewOptions64( c.bar = progressbar.NewOptions64(
c.FilesToTransfer[c.FilesToTransferCurrentNum].Size, c.FilesToTransfer[c.FilesToTransferCurrentNum].Size,
progressbar.OptionOnCompletion(func() { progressbar.OptionOnCompletion(func() {
@ -1791,14 +1920,14 @@ func (c *Client) setBar() {
} }
func (c *Client) receiveData(i int) { func (c *Client) receiveData(i int) {
log.Debugf("%d receiving data", i) log.Tracef("%d receiving data", i)
for { for {
data, err := c.conn[i+1].Receive() data, err := c.conn[i+1].Receive()
if err != nil { if err != nil {
break break
} }
if bytes.Equal(data, []byte{1}) { if bytes.Equal(data, []byte{1}) {
log.Debug("got ping") log.Trace("got ping")
continue continue
} }
@ -1874,62 +2003,66 @@ func (c *Client) sendData(i int) {
curi := float64(0) curi := float64(0)
for { for {
// Read file // Read file
data := make([]byte, models.TCP_BUFFER_SIZE/2) var n int
// log.Debugf("%d trying to read", i) var errRead error
n, errRead := c.fread.ReadAt(data, readingPos)
// log.Debugf("%d read %d bytes", i, n)
readingPos += int64(n)
if c.limiter != nil {
r := c.limiter.ReserveN(time.Now(), n)
log.Debugf("Limiting Upload for %d", r.Delay())
time.Sleep(r.Delay())
}
if math.Mod(curi, float64(len(c.Options.RelayPorts))) == float64(i) { if math.Mod(curi, float64(len(c.Options.RelayPorts))) == float64(i) {
// check to see if this is a chunk that the recipient wants data := make([]byte, models.TCP_BUFFER_SIZE/2)
usableChunk := true n, errRead = c.fread.ReadAt(data, readingPos)
c.mutex.Lock() if c.limiter != nil {
if len(c.chunkMap) != 0 { r := c.limiter.ReserveN(time.Now(), n)
if _, ok := c.chunkMap[pos]; !ok { log.Debugf("Limiting Upload for %d", r.Delay())
usableChunk = false time.Sleep(r.Delay())
} else {
delete(c.chunkMap, pos)
}
} }
c.mutex.Unlock() if n > 0 {
if usableChunk { // check to see if this is a chunk that the recipient wants
// log.Debugf("sending chunk %d", pos) usableChunk := true
posByte := make([]byte, 8) c.mutex.Lock()
binary.LittleEndian.PutUint64(posByte, pos) if len(c.chunkMap) != 0 {
var err error if _, ok := c.chunkMap[pos]; !ok {
var dataToSend []byte usableChunk = false
if c.Options.NoCompress { } else {
dataToSend, err = crypt.Encrypt( delete(c.chunkMap, pos)
append(posByte, data[:n]...), }
c.Key, }
) c.mutex.Unlock()
} else { if usableChunk {
dataToSend, err = crypt.Encrypt( // log.Debugf("sending chunk %d", pos)
compress.Compress( posByte := make([]byte, 8)
binary.LittleEndian.PutUint64(posByte, pos)
var err error
var dataToSend []byte
if c.Options.NoCompress {
dataToSend, err = crypt.Encrypt(
append(posByte, data[:n]...), append(posByte, data[:n]...),
), c.Key,
c.Key, )
) } else {
} dataToSend, err = crypt.Encrypt(
if err != nil { compress.Compress(
panic(err) append(posByte, data[:n]...),
} ),
c.Key,
)
}
if err != nil {
panic(err)
}
err = c.conn[i+1].Send(dataToSend) err = c.conn[i+1].Send(dataToSend)
if err != nil { if err != nil {
panic(err) panic(err)
}
c.bar.Add(n)
c.TotalSent += int64(n)
// time.Sleep(100 * time.Millisecond)
} }
c.bar.Add(n)
c.TotalSent += int64(n)
// time.Sleep(100 * time.Millisecond)
} }
} }
if n == 0 {
n = models.TCP_BUFFER_SIZE / 2
}
readingPos += int64(n)
curi++ curi++
pos += uint64(n) pos += uint64(n)

View File

@ -10,7 +10,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/schollz/croc/v9/src/tcp" "github.com/schollz/croc/v10/src/tcp"
log "github.com/schollz/logger" log "github.com/schollz/logger"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@ -528,7 +528,7 @@ main() {
local autocomplete_install_rcode local autocomplete_install_rcode
croc_bin_name="croc" croc_bin_name="croc"
croc_version="9.6.14" croc_version="10.0.7"
croc_dl_ext="tar.gz" croc_dl_ext="tar.gz"
croc_base_url="https://github.com/schollz/croc/releases/download" croc_base_url="https://github.com/schollz/croc/releases/download"
prefix="${1}" prefix="${1}"

View File

@ -3,9 +3,9 @@ package message
import ( import (
"encoding/json" "encoding/json"
"github.com/schollz/croc/v9/src/comm" "github.com/schollz/croc/v10/src/comm"
"github.com/schollz/croc/v9/src/compress" "github.com/schollz/croc/v10/src/compress"
"github.com/schollz/croc/v9/src/crypt" "github.com/schollz/croc/v10/src/crypt"
log "github.com/schollz/logger" log "github.com/schollz/logger"
) )

View File

@ -7,8 +7,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/schollz/croc/v9/src/comm" "github.com/schollz/croc/v10/src/comm"
"github.com/schollz/croc/v9/src/crypt" "github.com/schollz/croc/v10/src/crypt"
log "github.com/schollz/logger" log "github.com/schollz/logger"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -84,7 +84,7 @@ func TestSend(t *testing.T) {
} }
}() }()
time.Sleep(300 * time.Millisecond) time.Sleep(800 * time.Millisecond)
a, err := comm.NewConnection("127.0.0.1:"+port, 10*time.Minute) a, err := comm.NewConnection("127.0.0.1:"+port, 10*time.Minute)
assert.Nil(t, err) assert.Nil(t, err)
m := Message{Type: TypeMessage, Message: "hello, world"} m := Message{Type: TypeMessage, Message: "hello, world"}

View File

@ -7,7 +7,7 @@ import (
"os" "os"
"path" "path"
"github.com/schollz/croc/v9/src/utils" "github.com/schollz/croc/v10/src/utils"
) )
// TCP_BUFFER_SIZE is the maximum packet size // TCP_BUFFER_SIZE is the maximum packet size
@ -44,8 +44,8 @@ var publicDNS = []string{
"[2620:119:53::53]", // Cisco OpenDNS "[2620:119:53::53]", // Cisco OpenDNS
} }
func getConfigFile() (fname string, err error) { func getConfigFile(requireValidPath bool) (fname string, err error) {
configFile, err := utils.GetConfigDir() configFile, err := utils.GetConfigDir(requireValidPath)
if err != nil { if err != nil {
return return
} }
@ -66,14 +66,14 @@ func init() {
} }
if doRemember { if doRemember {
// save in config file // save in config file
fname, err := getConfigFile() fname, err := getConfigFile(true)
if err == nil { if err == nil {
f, _ := os.Create(fname) f, _ := os.Create(fname)
f.Close() f.Close()
} }
} }
if !INTERNAL_DNS { if !INTERNAL_DNS {
fname, err := getConfigFile() fname, err := getConfigFile(false)
if err == nil { if err == nil {
INTERNAL_DNS = utils.Exists(fname) INTERNAL_DNS = utils.Exists(fname)
} }

View File

@ -11,9 +11,9 @@ import (
log "github.com/schollz/logger" log "github.com/schollz/logger"
"github.com/schollz/pake/v3" "github.com/schollz/pake/v3"
"github.com/schollz/croc/v9/src/comm" "github.com/schollz/croc/v10/src/comm"
"github.com/schollz/croc/v9/src/crypt" "github.com/schollz/croc/v10/src/crypt"
"github.com/schollz/croc/v9/src/models" "github.com/schollz/croc/v10/src/models"
) )
type server struct { type server struct {
@ -516,7 +516,7 @@ func ConnectToTCPServer(address, password, room string, timelimit ...time.Durati
} }
banner = strings.Split(string(data), "|||")[0] banner = strings.Split(string(data), "|||")[0]
ipaddr = strings.Split(string(data), "|||")[1] ipaddr = strings.Split(string(data), "|||")[1]
log.Debug("sending room") log.Debugf("sending room; %s", room)
bSend, err = crypt.Encrypt([]byte(room), strongKeyForEncryption) bSend, err = crypt.Encrypt([]byte(room), strongKeyForEncryption)
if err != nil { if err != nil {
log.Debug(err) log.Debug(err)

View File

@ -21,32 +21,40 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
"unicode"
"github.com/cespare/xxhash" "github.com/cespare/xxhash"
"github.com/kalafut/imohash" "github.com/kalafut/imohash"
"github.com/minio/highwayhash"
"github.com/schollz/mnemonicode" "github.com/schollz/mnemonicode"
"github.com/schollz/progressbar/v3"
) )
const NbPinNumbers = 4 const NbPinNumbers = 4
const NbBytesWords = 4 const NbBytesWords = 4
// Get or create home directory // Get or create home directory
func GetConfigDir() (homedir string, err error) { func GetConfigDir(requireValidPath bool) (homedir string, err error) {
homedir, err = os.UserHomeDir()
if err != nil {
return
}
if envHomedir, isSet := os.LookupEnv("CROC_CONFIG_DIR"); isSet { if envHomedir, isSet := os.LookupEnv("CROC_CONFIG_DIR"); isSet {
homedir = envHomedir homedir = envHomedir
} else if xdgConfigHome, isSet := os.LookupEnv("XDG_CONFIG_HOME"); isSet { } else if xdgConfigHome, isSet := os.LookupEnv("XDG_CONFIG_HOME"); isSet {
homedir = path.Join(xdgConfigHome, "croc") homedir = path.Join(xdgConfigHome, "croc")
} else { } else {
homedir, err = os.UserHomeDir()
if err != nil {
if !requireValidPath {
err = nil
homedir = ""
}
return
}
homedir = path.Join(homedir, ".config", "croc") homedir = path.Join(homedir, ".config", "croc")
} }
if _, err = os.Stat(homedir); os.IsNotExist(err) { if requireValidPath {
err = os.MkdirAll(homedir, 0o700) if _, err = os.Stat(homedir); os.IsNotExist(err) {
err = os.MkdirAll(homedir, 0o700)
}
} }
return return
} }
@ -71,7 +79,11 @@ func GetInput(prompt string) string {
// HashFile returns the hash of a file or, in case of a symlink, the // HashFile returns the hash of a file or, in case of a symlink, the
// SHA256 hash of its target. Takes an argument to specify the algorithm to use. // SHA256 hash of its target. Takes an argument to specify the algorithm to use.
func HashFile(fname string, algorithm string) (hash256 []byte, err error) { func HashFile(fname string, algorithm string, showProgress ...bool) (hash256 []byte, err error) {
doShowProgress := false
if len(showProgress) > 0 {
doShowProgress = showProgress[0]
}
var fstats os.FileInfo var fstats os.FileInfo
fstats, err = os.Lstat(fname) fstats, err = os.Lstat(fname)
if err != nil { if err != nil {
@ -89,16 +101,59 @@ func HashFile(fname string, algorithm string) (hash256 []byte, err error) {
case "imohash": case "imohash":
return IMOHashFile(fname) return IMOHashFile(fname)
case "md5": case "md5":
return MD5HashFile(fname) return MD5HashFile(fname, doShowProgress)
case "xxhash": case "xxhash":
return XXHashFile(fname) return XXHashFile(fname, doShowProgress)
case "highway":
return HighwayHashFile(fname, doShowProgress)
} }
err = fmt.Errorf("unspecified algorithm") err = fmt.Errorf("unspecified algorithm")
return return
} }
// HighwayHashFile returns highwayhash of a file
func HighwayHashFile(fname string, doShowProgress bool) (hashHighway []byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
}
defer f.Close()
key, err := hex.DecodeString("1553c5383fb0b86578c3310da665b4f6e0521acf22eb58a99532ffed02a6b115")
if err != nil {
return
}
h, err := highwayhash.New(key)
if err != nil {
err = fmt.Errorf("could not create highwayhash: %s", err.Error())
return
}
if doShowProgress {
stat, _ := f.Stat()
fnameShort := path.Base(fname)
if len(fnameShort) > 20 {
fnameShort = fnameShort[:20] + "..."
}
bar := progressbar.NewOptions64(stat.Size(),
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowBytes(true),
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
progressbar.OptionClearOnFinish(),
)
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
return
}
} else {
if _, err = io.Copy(h, f); err != nil {
return
}
}
hashHighway = h.Sum(nil)
return
}
// MD5HashFile returns MD5 hash // MD5HashFile returns MD5 hash
func MD5HashFile(fname string) (hash256 []byte, err error) { func MD5HashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
f, err := os.Open(fname) f, err := os.Open(fname)
if err != nil { if err != nil {
return return
@ -106,8 +161,25 @@ func MD5HashFile(fname string) (hash256 []byte, err error) {
defer f.Close() defer f.Close()
h := md5.New() h := md5.New()
if _, err = io.Copy(h, f); err != nil { if doShowProgress {
return stat, _ := f.Stat()
fnameShort := path.Base(fname)
if len(fnameShort) > 20 {
fnameShort = fnameShort[:20] + "..."
}
bar := progressbar.NewOptions64(stat.Size(),
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowBytes(true),
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
progressbar.OptionClearOnFinish(),
)
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
return
}
} else {
if _, err = io.Copy(h, f); err != nil {
return
}
} }
hash256 = h.Sum(nil) hash256 = h.Sum(nil)
@ -131,7 +203,7 @@ func IMOHashFileFull(fname string) (hash []byte, err error) {
} }
// XXHashFile returns the xxhash of a file // XXHashFile returns the xxhash of a file
func XXHashFile(fname string) (hash256 []byte, err error) { func XXHashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
f, err := os.Open(fname) f, err := os.Open(fname)
if err != nil { if err != nil {
return return
@ -139,8 +211,25 @@ func XXHashFile(fname string) (hash256 []byte, err error) {
defer f.Close() defer f.Close()
h := xxhash.New() h := xxhash.New()
if _, err = io.Copy(h, f); err != nil { if doShowProgress {
return stat, _ := f.Stat()
fnameShort := path.Base(fname)
if len(fnameShort) > 20 {
fnameShort = fnameShort[:20] + "..."
}
bar := progressbar.NewOptions64(stat.Size(),
progressbar.OptionSetWriter(os.Stderr),
progressbar.OptionShowBytes(true),
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
progressbar.OptionClearOnFinish(),
)
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
return
}
} else {
if _, err = io.Copy(h, f); err != nil {
return
}
} }
hash256 = h.Sum(nil) hash256 = h.Sum(nil)
@ -433,6 +522,12 @@ func UnzipDirectory(destination string, source string) error {
filePath := filepath.Join(destination, f.Name) filePath := filepath.Join(destination, f.Name)
fmt.Fprintf(os.Stderr, "\r\033[2K") fmt.Fprintf(os.Stderr, "\r\033[2K")
fmt.Fprintf(os.Stderr, "\rUnzipping file %s", filePath) fmt.Fprintf(os.Stderr, "\rUnzipping file %s", filePath)
// Issue #593 conceal path traversal vulnerability
// make sure the filepath does not have ".."
filePath = filepath.Clean(filePath)
if strings.Contains(filePath, "..") {
log.Fatalf("Invalid file path %s\n", filePath)
}
if f.FileInfo().IsDir() { if f.FileInfo().IsDir() {
os.MkdirAll(filePath, os.ModePerm) os.MkdirAll(filePath, os.ModePerm)
continue continue
@ -442,6 +537,16 @@ func UnzipDirectory(destination string, source string) error {
log.Fatalln(err) log.Fatalln(err)
} }
// check if file exists
if _, err := os.Stat(filePath); err == nil {
prompt := fmt.Sprintf("\nOverwrite '%s'? (y/N) ", filePath)
choice := strings.ToLower(GetInput(prompt))
if choice != "y" && choice != "yes" {
fmt.Fprintf(os.Stderr, "Skipping '%s'\n", filePath)
continue
}
}
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)
@ -462,3 +567,23 @@ func UnzipDirectory(destination string, source string) error {
fmt.Fprintf(os.Stderr, "\n") fmt.Fprintf(os.Stderr, "\n")
return nil return nil
} }
// ValidFileName checks if a filename is valid
// by making sure it has no invisible characters
func ValidFileName(fname string) bool {
clean1 := strings.Map(func(r rune) rune {
if unicode.IsGraphic(r) {
return r
}
return -1
}, fname)
clean2 := strings.Map(func(r rune) rune {
if unicode.IsPrint(r) {
return r
}
return -1
}, fname)
return (fname == clean1) && (fname == clean2)
}

View File

@ -24,7 +24,7 @@ func BenchmarkMD5(b *testing.B) {
bigFile() bigFile()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
MD5HashFile("bigfile.test") MD5HashFile("bigfile.test", false)
} }
} }
@ -32,7 +32,7 @@ func BenchmarkXXHash(b *testing.B) {
bigFile() bigFile()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
XXHashFile("bigfile.test") XXHashFile("bigfile.test", false)
} }
} }
@ -44,6 +44,14 @@ func BenchmarkImoHash(b *testing.B) {
} }
} }
func BenchmarkHighwayHash(b *testing.B) {
bigFile()
b.ResetTimer()
for i := 0; i < b.N; i++ {
HighwayHashFile("bigfile.test", false)
}
}
func BenchmarkImoHashFull(b *testing.B) { func BenchmarkImoHashFull(b *testing.B) {
bigFile() bigFile()
b.ResetTimer() b.ResetTimer()
@ -78,10 +86,20 @@ func TestExists(t *testing.T) {
func TestMD5HashFile(t *testing.T) { func TestMD5HashFile(t *testing.T) {
bigFile() bigFile()
defer os.Remove("bigfile.test") defer os.Remove("bigfile.test")
b, err := MD5HashFile("bigfile.test") b, err := MD5HashFile("bigfile.test", false)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "8304ff018e02baad0e3555bade29a405", fmt.Sprintf("%x", b)) assert.Equal(t, "8304ff018e02baad0e3555bade29a405", fmt.Sprintf("%x", b))
_, err = MD5HashFile("bigfile.test.nofile") _, err = MD5HashFile("bigfile.test.nofile", false)
assert.NotNil(t, err)
}
func TestHighwayHashFile(t *testing.T) {
bigFile()
defer os.Remove("bigfile.test")
b, err := HighwayHashFile("bigfile.test", false)
assert.Nil(t, err)
assert.Equal(t, "3c32999529323ed66a67aeac5720c7bf1301dcc5dca87d8d46595e85ff990329", fmt.Sprintf("%x", b))
_, err = HighwayHashFile("bigfile.test.nofile", false)
assert.NotNil(t, err) assert.NotNil(t, err)
} }
@ -96,10 +114,10 @@ func TestIMOHashFile(t *testing.T) {
func TestXXHashFile(t *testing.T) { func TestXXHashFile(t *testing.T) {
bigFile() bigFile()
defer os.Remove("bigfile.test") defer os.Remove("bigfile.test")
b, err := XXHashFile("bigfile.test") b, err := XXHashFile("bigfile.test", false)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "4918740eb5ccb6f7", fmt.Sprintf("%x", b)) assert.Equal(t, "4918740eb5ccb6f7", fmt.Sprintf("%x", b))
_, err = XXHashFile("nofile") _, err = XXHashFile("nofile", false)
assert.NotNil(t, err) assert.NotNil(t, err)
} }
@ -208,11 +226,37 @@ func TestGetRandomName(t *testing.T) {
assert.NotEmpty(t, name) assert.NotEmpty(t, name)
} }
func intSliceSame(a, b []int) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
func TestFindOpenPorts(t *testing.T) { func TestFindOpenPorts(t *testing.T) {
openPorts := FindOpenPorts("127.0.0.1", 9009, 4) openPorts := FindOpenPorts("127.0.0.1", 9009, 4)
assert.Equal(t, []int{9009, 9010, 9011, 9012}, openPorts) if !intSliceSame(openPorts, []int{9009, 9010, 9011, 9012}) && !intSliceSame(openPorts, []int{9014, 9015, 9016, 9017}) {
t.Errorf("openPorts: %v", openPorts)
}
} }
func TestIsLocalIP(t *testing.T) { func TestIsLocalIP(t *testing.T) {
assert.True(t, IsLocalIP("192.168.0.14:9009")) assert.True(t, IsLocalIP("192.168.0.14:9009"))
} }
func TestValidFileName(t *testing.T) {
// contains regular characters
assert.True(t, ValidFileName("中文.csl"))
// contains regular characters
assert.True(t, ValidFileName("[something].csl"))
// contains regular characters
assert.True(t, ValidFileName("[(something)].csl"))
// contains invisible character
assert.False(t, ValidFileName("D中文.cslouglas"))
}