Compare commits

...

1733 Commits
v0.3.0 ... main

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 483c5255bb chore: bump version to 9.6.14 2024-03-11 15:50:04 -07:00
Zack Scholl 03e6dcd220 Merge branch 'main' of github.com:schollz/croc 2024-03-11 22:50:02 +00:00
Zack Scholl 22ddbd83c2 chore: update deps 2024-03-11 15:49:09 -07:00
Zack Scholl 6b930c365b Merge branch 'main' of github.com:schollz/croc 2024-03-11 22:49:03 +00:00
Zack 1f6851f33b
Merge pull request #680 from schollz/dependabot/github_actions/softprops/action-gh-release-2
Bump softprops/action-gh-release from 1 to 2
2024-03-11 15:48:20 -07:00
Zack 61224b4e6b
Merge pull request #678 from schollz/dependabot/go_modules/github.com/stretchr/testify-1.9.0
Bump github.com/stretchr/testify from 1.8.2 to 1.9.0
2024-03-11 15:48:07 -07:00
Zack Scholl 6f2771e7b5 Merge branch 'main' of github.com:schollz/croc 2024-03-11 13:46:03 +00:00
Zack c21beccb7a
Merge pull request #679 from bitraid/fix-win-build
Fix Windows builds
2024-03-11 06:45:41 -07:00
dependabot[bot] 40f5e9ca1e
Bump softprops/action-gh-release from 1 to 2
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 08:56:10 +00:00
bitraid ed8c0475bf
Fix Windows builds 2024-03-09 22:31:27 +02:00
dependabot[bot] d7d7d3c8dc
Bump github.com/stretchr/testify from 1.8.2 to 1.9.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.2 to 1.9.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.2...v1.9.0)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-05 04:57:38 +00:00
Zack Scholl 945ac74690 Merge branch 'main' of github.com:schollz/croc 2024-03-05 04:57:05 +00:00
Zack Scholl fff6f48001 chore: update dependencies 2024-03-04 20:56:40 -08:00
Zack Scholl 28ef8e99ac Merge branch 'main' of github.com:schollz/croc 2024-02-22 22:41:05 +00:00
Zack 28bb36b321 bump version 2024-02-22 14:40:20 -08:00
Zack Scholl ab2cb477a8 Merge branch 'main' of github.com:schollz/croc 2024-02-22 22:40:05 +00:00
Zack abc5029fce update release with LICENSE 2024-02-22 14:39:57 -08:00
Zack e7f67ebea7 update date 2024-02-22 14:39:50 -08:00
Zack Scholl c7f0228786 Merge branch 'main' of github.com:schollz/croc 2024-02-22 22:35:05 +00:00
Zack 741714504a
Merge pull request #671 from dbohdan/main
Build release binaries for DragonFly/Free/Net/OpenBSD
2024-02-22 14:34:06 -08:00
D. Bohdan be8a6689ff build release bins for DragonFly/Free/Net/OpenBSD 2024-02-22 21:22:32 +00:00
Zack Scholl de9c54e57a Merge branch 'main' of github.com:schollz/croc 2024-02-20 15:59:03 +00:00
Zack 53fc9ebd99 bump version 2024-02-20 07:58:27 -08:00
Zack 4159ba7668 do static builds of croc
following https://github.com/golang/go/issues/26492#issuecomment-435462350
2024-02-20 07:57:49 -08:00
Zack Scholl 064f84ccd3 Merge branch 'main' of github.com:schollz/croc 2024-02-19 15:55:51 +00:00
Zack 8ac1e3a501 bump version 2024-02-19 07:47:23 -08:00
Zack 11bc4eecc6 update deps 2024-02-19 07:46:53 -08:00
Zack d92cff92b9 add arm/arm64 builds for windows fixes #664 2024-02-19 07:46:35 -08:00
Zack 00f12b5742
Merge pull request #663 from TravisRoad/main
remove unnecessary trailing newline character when stdout is enabled
2024-02-18 06:32:28 -08:00
Travis 4f1f57b1ba remove unnecessary trailing newline character when stdout is enabled 2024-02-18 10:17:35 +08:00
Zack a240a4b982
Merge pull request #657 from schollz/dependabot/github_actions/actions/stale-9
Bump actions/stale from 5 to 9
2024-02-17 10:29:47 -08:00
Zack 508e0be335
Merge pull request #662 from qk-santi/ports-and-transfers
define ports by amount, not individually - v2
2024-02-17 10:28:58 -08:00
qk-santi e1644401da version compatible basePort and transfers 2024-02-17 19:09:53 +01:00
qk-santi c83eb59963 Revert "define ports by amount, not individually"
This reverts commit 87152f8706.
2024-02-17 18:41:41 +01:00
Zack f874e30151 revert go version back to go.1.21 because of glibc errors 2024-02-16 06:56:33 -08:00
Zack b278f5a41d bump version 2024-02-16 06:56:06 -08: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
Zack 30a6b14443
Merge pull request #659 from qk-santi/hide-relay-not-used
hide relay param if not going to be used
2024-02-12 06:37:28 -07:00
qk-santi 87152f8706 define ports by amount, not individually 2024-02-12 09:58:51 +01:00
qk-santi 48eb2a2a7c hide relay param if not going to be used 2024-02-12 09:30:20 +01:00
dependabot[bot] 816ad09a50
Bump actions/stale from 5 to 9
Bumps [actions/stale](https://github.com/actions/stale) from 5 to 9.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v5...v9)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-09 09:01:53 +00:00
Zack a2228e80c2
Create stale.yml 2024-02-08 13:43:05 -07:00
Zack Scholl 230de9184d bump version 2024-02-08 13:39:45 -07:00
Zack 3c781069ca
Merge pull request #653 from schollz/dependabot/go_modules/golang.org/x/crypto-0.19.0
Bump golang.org/x/crypto from 0.18.0 to 0.19.0
2024-02-08 13:38:12 -07:00
Zack 7274a8bd4b
Merge pull request #655 from schollz/schollz/issue650
add build for windows 7
2024-02-08 13:37:54 -07:00
Zack Scholl 3382306342 add build for windows 7 2024-02-08 13:37:10 -07:00
dependabot[bot] ad47739c8f
Bump golang.org/x/crypto from 0.18.0 to 0.19.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.18.0 to 0.19.0.
- [Commits](https://github.com/golang/crypto/compare/v0.18.0...v0.19.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-02-08 08:07:15 +00:00
Zack 2f33b14b3d
Merge pull request #581 from sitiom/patch-1
switch winget releaser runner to `ubuntu-latest`
2024-02-06 18:12:51 -08:00
Zack 4025efcd48 bump the default.txt 2024-02-06 15:58:18 -08:00
Zack f41a2afead bump version and fix installer 2024-02-06 15:51:07 -08:00
Zack ba75f7badb add release workflow for generating binaries 2024-02-06 15:37:28 -08:00
Zack 55c954117a update deps 2024-02-06 14:33:01 -08:00
Zack 4d083f8d10
Merge pull request #646 from rehanone/fix-docker-deplyment
Fix for the failing CD build
2024-02-06 08:05:08 -08:00
Rehan Mahmood 9ad2af18bd Added the `gcc` and `musl-dev` packages in the builder layer of the Dockerfile. 2024-01-28 14:38:01 -05:00
Zack 47fc96b98f
Merge pull request #645 from rehanone/fix-docker-deplyment
Update and fix the docker image deplyment build
2024-01-25 07:59:36 -08:00
Rehan Mahmood d4bba88fb1 Update and fix the docker image deplyment build 2024-01-25 10:02:01 -05:00
Zack Scholl c1367671b6 bump 9.6.6 2023-11-09 06:56:42 -08:00
Zack Scholl 1e572067ec bump 9.6.6 2023-11-09 06:56:29 -08:00
Zack Scholl 8aa9f040f6 bump 9.6.6 2023-11-09 06:53:42 -08:00
Zack Scholl 96bb34485e update deps 2023-11-09 06:51:31 -08:00
Zack 159f0f8d9b
Merge pull request #625 from gravetii/patch-1
Fix minor error in README
2023-11-05 07:30:14 -08:00
Sandeep c4d5c89e5f
Fix minor error in README 2023-11-03 11:20:41 +05:30
Zack 6ac67b68fc
Merge pull request #570 from PThorpe92/main
.gitignore support
2023-09-23 07:09:30 -07:00
PThorpe92 0af35d7149
feat: add support to respect .gitignore files 2023-09-22 21:15:27 -04:00
Zack f91c7a9948
Merge pull request #587 from ferebee/main
fix architecture detection for Apple Silicon
2023-09-03 19:35:53 -07:00
Zack cff8cddd13
Merge pull request #589 from zx9597446/main
zip file bug on windows and linux
2023-08-18 11:00:46 +02:00
zx9597446 d724f11297 Here is the English translation:
If there are directories in a zip file compressed on the Windows platform, the "\\" in the filepath will cause the files to be extracted normally on Linux, and ls will show filenames containing single quotes.

So when compressing, I replace "\\" with "/" so that it seems there are no issues on both Windows and Linux.
2023-08-17 12:07:07 +08:00
ferebee 80aabea29b fix architecture detection for Apple Silicon
fix auto-install on macOS Apple Silicon, which reports architecture "arm64" on uname -a rather than "aarch64"
2023-08-09 11:42:23 +02:00
sitiom f8bb011eac
switch winget releaser runner to `ubuntu-latest` 2023-07-07 08:52:14 +08:00
Zack Scholl ef68dfa54c bump 9.6.5 2023-07-06 10:10:57 -07:00
Zack Scholl 8ab65d06b5 bump 9.6.5 2023-07-06 10:10:39 -07:00
Zack Scholl 9c82914e7c update deps 2023-07-06 10:00:05 -07:00
Zack 95717f16c9
Merge pull request #579 from glitsj16/systemd-unit
croc.service: use DynamicUser
2023-06-21 05:58:58 -07:00
glitsj16 5a58ae294b
croc.service: use DynamicUser 2023-06-21 01:46:47 +00:00
Zack Scholl 0aa5c80393 upgrade dependencies 2023-05-08 17:39:18 +00:00
Zack 23a8904193
Merge pull request #563 from N0mansky/main
Feat: support http proxy as a complementary way to use in network limited environments.
2023-04-12 09:03:53 -07:00
N0mansky d5e63cd0bf Update: update error messages for http proxy 2023-04-12 18:17:25 +08:00
N0mansky 1b1dc5cdfe Feat: support http proxy as a complementary way to use in network limited environments. 2023-04-12 18:04:15 +08:00
Zack cd1162f85c
Merge pull request #553 from goggle/typos01
Fix some typos
2023-03-27 08:36:56 -07:00
Alexander Seiler ad7a22b218
Fix some typos
Signed-off-by: Alexander Seiler <seileralex@gmail.com>
2023-03-27 17:13:09 +02:00
Zack e3a18cd7a7
Merge pull request #547 from schollz/dependabot/github_actions/docker/setup-buildx-action-2
Bump docker/setup-buildx-action from 1 to 2
2023-03-27 07:43:21 -07:00
Zack 8611bfa44a
Merge pull request #550 from schollz/dependabot/github_actions/actions/setup-go-4
Bump actions/setup-go from 2 to 4
2023-03-27 07:42:58 -07:00
Zack Scholl b3c0625659 localhost -> 127.0.0.1 Fixes #513 2023-03-20 09:16:07 -07:00
dependabot[bot] 40e5893bb8
Bump actions/setup-go from 2 to 4
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2...v4)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-16 09:12:12 +00:00
Zack e1b49e6d1c
Merge pull request #549 from BayLee4/main
Enhance tab completion
2023-03-15 08:11:00 -07:00
BayLee4 fae2e81b4a
Enhance tab completion 2023-03-15 10:03:38 +01:00
BayLee4 f5a02df17b
Merge pull request #1 from schollz/main
Merge upstream
2023-03-15 07:40:29 +00:00
dependabot[bot] d813aa2fa9
Bump docker/setup-buildx-action from 1 to 2
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 1 to 2.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-14 12:01:02 +00:00
Zack 8d8d06557e
Merge pull request #534 from sitiom/winget-releaser
add winget releaser workflow
2023-03-14 05:00:19 -07:00
Zack Scholl 3ae46c3c18 bump 9.6.4 2023-03-14 04:52:15 -07:00
Zack Scholl 1fce28e72f remove twitter 2023-03-14 04:51:47 -07:00
Zack Scholl ac3caa5564 bump 9.6.4 2023-03-14 04:50:55 -07:00
Zack Scholl 790ee9e6eb bump 9.6.4 2023-03-14 04:50:29 -07:00
Zack Scholl 0656bb7851 bump 9.6.4 2023-03-14 04:50:10 -07:00
Zack Scholl 5ed8204cb1 bump 9.6.4 2023-03-14 04:50:00 -07:00
Zack Scholl 1220d54a65 bump 9.6.4 2023-03-14 04:41:22 -07:00
Zack Scholl 642d20b48d update deps 2023-03-14 04:39:05 -07:00
Zack 58bb226ba5
Merge pull request #542 from stefins/go-version
Upgrade Go version to 1.20 and dependencies to latest
2023-03-14 04:36:56 -07:00
stefins 080c21b66b
Change go version to 1.20 in CI 2023-03-10 20:59:45 +05:30
stefins 4944355b75
Upgrade Go version to 1.20 and dependencies to latest 2023-03-10 20:59:33 +05:30
Zack Scholl 3c1d60d6d2 bump 9.6.3 2023-02-20 07:34:32 -08:00
Zack Scholl 5bdd4453cd bump 9.6.3 2023-02-20 07:34:04 -08:00
Zack Scholl 5b333fc85c bump 9.6.3 2023-02-20 07:33:52 -08:00
Zack Scholl 90e4e33dcd bump 9.6.3 2023-02-20 07:33:34 -08:00
Zack Scholl 3135bd74e3 bump 9.6.3 2023-02-20 07:21:24 -08:00
Zack Scholl 7c98ae3d5a deps 2023-02-20 07:19:47 -08:00
sitiom 908f33cd61
add dependabot 2023-02-13 11:52:34 +08:00
sitiom 9eaba7be7c
add Winget installation instructions 2023-02-12 23:45:11 +08:00
Ryan Caezar Itang b3db9d88c1
add winget releaser workflow 2023-02-12 23:44:34 +08:00
Zack Scholl 9006cde1b3 update deps 2023-02-10 11:59:48 -08:00
Zack 8f75bb8299
Merge pull request #533 from stefins/patch-1
Update CI to run on main branch events
2023-02-10 11:59:21 -08:00
Zack faf64aadf1
Merge pull request #532 from stefins/chmod-file
Chmod new file based on the source file mode
2023-02-10 11:58:59 -08:00
stefins 65760b1189
Update CI to run on main branch events 2023-02-11 01:18:43 +05:30
stefins 24679d4e02
Chmod new file based on the source file mode 2023-02-10 14:53:06 +05:30
Zack Scholl 8b9977a7c4 update 2023-02-07 05:46:10 -08:00
Zack ae71b4b63b
Merge pull request #528 from chncaption/oscs_fix_cfds588au51u2n4fthm0
fix(sec): upgrade gopkg.in/yaml.v3 to 3.0.0
2023-02-07 05:45:44 -08:00
Zack Scholl c462b5948f update go.mod/go.sum 2023-02-07 05:44:17 -08:00
Zack a2c1dc6a89
Merge pull request #526 from BayLee4/main
Implement tab completion for words
2023-02-07 05:40:41 -08:00
chncaption 98391bff63 update gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c to 3.0.0 2023-02-02 22:03:21 +08:00
BayLee4 adadaba75e
Small optimization + consistent variable names style 2023-01-13 16:29:11 +01:00
BayLee4 0024beaedc
Implement tab completion for words 2023-01-12 19:23:50 +01:00
Zack Scholl 63feece074 add testing 2023-01-08 08:11:55 -08:00
Zack Scholl 9e280d7f48 update deps 2023-01-03 18:40:31 +00:00
Zack Scholl 7c7be95d6b update deps 2023-01-03 18:40:20 +00:00
Zack c20beb1be7
not reachable by twitter anymore 2022-12-16 16:35:06 -08:00
Zack Scholl e08c5e7f38 bump 9.6.2 2022-12-06 07:59:30 -08:00
Zack Scholl 3b819346fa bump 9.6.2 2022-12-06 07:58:30 -08:00
Zack Scholl 2467411bae fix install tests 2022-12-06 07:58:15 -08:00
Zack Scholl b436b31970 update deps 2022-12-06 07:45:07 -08:00
Zack Scholl e3ce565ca6 fix: allow remembering hash algorithm 2022-12-05 15:28:25 -08:00
Zack Scholl e04981698c update deps 2022-12-05 15:25:10 -08:00
Zack Scholl 07a67ed54e path -> fpath 2022-12-05 15:24:47 -08:00
Zack 9a8e584aca
Merge pull request #520 from taigrr/gofumpt
run through gofumpt
2022-12-05 15:22:10 -08:00
Tai Groot fa7ae114f5
run through gofumpt 2022-12-05 11:21:04 -08:00
Zack 8a4326bc0d
Merge pull request #519 from taigrr/workflow
update dockerfile to v1.19
2022-12-04 09:37:17 -08:00
Tai Groot ae20f2b5ac
update dockerfile 2022-12-01 21:45:10 -08:00
Zack Scholl cd6eb1ba53 update deps 2022-11-18 20:55:07 -08:00
Zack Scholl 8454008b45 update deps 2022-11-18 20:52:55 -08:00
Zack fce4629120
Merge pull request #515 from taigrr/workflow
Github CI go 1.18 -> 1.19
2022-11-18 20:47:36 -08:00
Tai Groot fd0db2ad55
upgrade github ci workflow 2022-10-30 20:43:51 -07:00
Zack 7f9688c7a1
Merge pull request #512 from IrishMaestro/revision
Typo fix
2022-10-23 10:29:05 -07:00
IrishMaestro f1e15a54ee
Typo fix
typo fix for the word relative
2022-10-22 17:18:16 -05:00
Zack Scholl 0f7f449d7f bump 9.6.1 2022-10-17 13:44:09 -07:00
Zack Scholl b27982a742 update deps 2022-10-17 13:42:39 -07:00
Zack Scholl 30f5a3e84e revert back to flate instead of zstd 2022-09-16 09:19:58 -07:00
Zack Scholl 786fc8d34f update mods 2022-09-16 09:10:08 -07:00
Zack 8de4508876
Merge pull request #506 from V-R-Dighe/develop
Added zstd as a compression algorithm
2022-09-16 09:08:14 -07:00
VRDighe e640e4fce0 Replaced zstd package 2022-09-16 10:19:44 +05:30
VRDighe 4f8b2aba9b Added zstd as a compression algorithm 2022-09-13 20:08:07 +05:30
Zack 1517767129
addresses #496 gettings ports doing LAN 2022-08-12 12:00:26 -07:00
Zack Scholl 3dedd41557 update 2022-08-06 09:32:46 -07:00
Zack 69f939c0cd
Merge pull request #494 from chavacava/fix-493
fix #493: data race in cli.relay
2022-08-05 08:38:07 -07:00
Zack cd5872bd2d
Merge pull request #497 from cuishuang/main
fix some typos
2022-08-05 08:37:36 -07:00
cui fliter 1c6583f925 fix some typos
Signed-off-by: cui fliter <imcusg@gmail.com>
2022-08-05 20:41:18 +08:00
chavacava 40ac320261
fix #493: data race in cli.relay 2022-07-17 10:40:49 +02:00
Zack Scholl 1851327df7 bump 9.6.0 2022-07-08 16:41:04 -07:00
Zack Scholl 0e93f1e285 println -> print os.stderr 2022-07-07 10:46:49 -07:00
Zack Scholl 7e0814a57e update deps 2022-07-07 10:34:20 -07:00
Zack Scholl c6bcb79928 remove zip compression and add --zip to send command 2022-07-07 10:32:23 -07:00
Zack 134673691e
Merge pull request #488 from stefins/zip-folder
Added ability to zip a directory
2022-07-07 10:14:23 -07:00
Stefin d226ba536e Fixed relative path / bug 2022-07-07 18:56:37 +05:30
Stefin b50fe88474 Added support for sending relative folder 2022-07-07 02:58:49 +05:30
Stefin 37ae453ff7 Unzipping file at the reciever end 2022-07-07 00:06:11 +05:30
Stefin ee772c4cec Added UnzipDirectory function 2022-07-07 00:05:56 +05:30
Stefin ed030375e5 Modified the argument for GetFilesInfo in tests 2022-07-06 18:49:32 +05:30
Stefin ad36e21051 Handling the --zip flag 2022-07-06 18:48:19 +05:30
Stefin 4ea9a96d88 Added --zip CLI argument for zipping all the dir specified 2022-07-06 18:47:34 +05:30
Stefin f0f9b80bdf added ZipDirectory function 2022-07-06 18:46:02 +05:30
Zack 7a0c0a8200
Merge pull request #474 from tjanez/fedora-package
add Fedora instructions to README
2022-05-20 09:50:31 -07:00
Zack Scholl 5270755c15 bump 9.5.6 2022-05-18 16:57:22 -07:00
Zack Scholl b7e4a73c27 don't show number of folders if the number is 0 2022-05-18 16:57:00 -07:00
Zack Scholl da5d19ef28 update deps and ui 2022-05-18 16:53:28 -07:00
Zack c68cfcea8a
Merge pull request #478 from DasSkelett/fix/relay-address-behind-dns64
Fix relay IPv4 address resolution behind DNS64
2022-05-18 16:48:51 -07:00
DasSkelett 38ed8ecc3c
Fix relay IPv4 address resolution behind DNS64 2022-05-16 22:04:55 +02:00
Tadej Janež a5d3e00f2b
add Fedora instructions to README 2022-04-29 22:31:59 +02:00
Zack Scholl 9de06a6bf9 bump 9.5.5 2022-04-28 14:30:03 -07:00
Zack Scholl a6a3a57361 update deps 2022-04-28 14:29:42 -07:00
Zack 148c1a6cdd
Merge pull request #470 from iulius98/master
Fixed #463 issue
2022-04-27 16:23:10 -07:00
Zack Scholl 817905cf5a bump 9.5.4 2022-04-27 08:25:06 -07:00
Zack Scholl 6158b42ad1 update deps 2022-04-27 08:23:43 -07:00
Zack Scholl 80539f27c3 avoid deadlock 2022-04-25 06:25:25 -07:00
Zack 35652e60a3
new support system 2022-04-13 06:42:08 -07:00
RCL98 2ad8b1f1ce #463 fixed display at receiving end 2022-04-13 02:23:10 +03:00
RCL98 b316c0159f #463 fixed croc tests for empty folders, and to work in Windows 2022-04-11 00:02:26 +03:00
RCL98 f78ee15605 #463 fixed display for empty folders 2022-04-11 00:00:47 +03:00
iulius98 15d0209a29 #463 added capability to send/receive empty folders 2022-04-09 01:38:22 +03:00
Zack 386c99d057
Merge pull request #462 from davide125/completion
Drop shebang for bash completion
2022-04-07 07:14:20 -07:00
Zack Scholl fd99a405fd bump 9.5.3 2022-04-07 06:05:16 -07:00
Zack Scholl 54f52e5427 bump 9.5.3 2022-04-07 06:04:46 -07:00
Zack Scholl ec949888d8 Merge branch 'master' of github.com:schollz/croc 2022-04-07 06:01:08 -07:00
Zack Scholl 0d52ead66e update default curve 2022-04-07 06:01:02 -07:00
Zack Scholl b715993435 bump 9.5.3 2022-04-07 05:59:24 -07:00
Zack Scholl 7e817e1cbf default to P-256 2022-04-07 05:52:54 -07:00
Zack 4abdbf1ad2
update to go 1.18 2022-04-06 21:48:39 -07:00
Zack Scholl 087c22d833 update readme 2022-04-03 15:21:35 -07:00
Zack Scholl 789b5bf607 update deps 2022-03-30 11:30:36 -07:00
Davide Cavalca e42f81a404 Drop shebang for bash completion 2022-02-27 08:40:56 -08:00
Zack Scholl 20bf7dd91d bump 9.5.2 2022-02-23 08:19:02 -08:00
Zack Scholl 4a8c19b115 bump 9.5.2 2022-02-23 08:16:50 -08:00
Zack Scholl a1a17ce6f7 bump 9.5.2 2022-02-23 08:09:02 -08:00
Zack Scholl 00c4d248fd bump 9.5.2 2022-02-23 08:08:43 -08:00
Zack Scholl 073196ccd2 bump 9.5.2 2022-02-23 08:07:23 -08:00
Zack Scholl 635b362ca0 tcp: send error on fail 2022-02-23 08:03:45 -08:00
Zack Scholl 53f35c1da0 fix ui when sending text 2022-02-23 07:57:40 -08:00
Zack 030ed2a03d
Merge pull request #456 from abhi12299/filenamePrefix
Fix renaming of file with prefix "croc-stdin" on receiver end
2022-02-23 07:52:27 -08:00
Zack Scholl c28d731a66 update deps 2022-02-23 07:31:45 -08:00
Zack Scholl ef6683b550 add more tests 2022-02-23 07:25:13 -08:00
Zack f6a75c8f53
Merge pull request #460 from iulius98/master
#431 fixed remote path
2022-02-23 07:14:46 -08:00
RCL98 7c1a59c102 #431 fixed remote folder name for Windows 2022-02-21 21:50:24 +02:00
iulius98 32a188fa85 #431 Integrate GetFilesInfo function with the code 2022-02-21 20:41:51 +02:00
RCL98 ce8fb796b3 #431 added file informations retrival functions to replace getPaths 2022-02-21 20:16:27 +02:00
Zack 1bd705d2e1
Merge pull request #459 from iulius98/master
#454 fixed local transfer
2022-02-20 07:57:34 -08:00
iulius98 1a635de69c #454 fixed local transfer 2022-02-20 17:40:50 +02:00
Zack 353ae0db16
add more information 2022-02-07 14:06:49 -08:00
Abhishek 9f66842322 fix sending file with prefix "croc-stdin" renaming on receiver end 2022-02-03 23:09:37 +05:30
Zack Scholl 94c0f66a26 bump 9.5.1 2022-02-03 08:51:19 -08:00
Zack Scholl b0e7d4d5df fix tests 2022-02-03 08:45:50 -08:00
Zack Scholl 9b5252d54c update deps 2022-02-03 08:40:49 -08:00
Zack Scholl 1d3c822ef3 allow remembering --internal-dns flag 2022-02-03 08:34:03 -08:00
Zack df78f3333d
Merge pull request #451 from voocel/fix_hash_err
fix hash file error
2022-01-06 04:43:50 -08:00
voocel b45e625298 fix hash file error 2022-01-06 17:44:43 +08:00
Zack Scholl 7390e7ed45 bump 9.5.0 2021-11-18 07:03:47 -08:00
Zack f210ef8877
Merge pull request #435 from AmeyShrivastava/fix-typos
Fix Typos
2021-11-17 10:52:29 -08:00
Amey Shrivastava 2964ede174 Fix Typos (revised)
This commit fixes spelling mistakes (typos) at a few places in the codebase.
(Includes requested corrections)
2021-11-17 23:50:32 +05:30
Zack Scholl cc837fa863 fix ports for tests 2021-11-17 10:11:35 -08:00
Zack Scholl 87bfdf11a8 update deps 2021-11-17 09:40:59 -08:00
Zack c30492609e
Merge pull request #432 from mbattista/master
added throttle upload feature
2021-11-17 09:37:50 -08:00
Zack 2f733891db
Merge pull request #440 from Juneezee/go1.17
build: upgrade to Go 1.17
2021-11-17 09:35:25 -08:00
Zack 3eb66284e0
Merge pull request #434 from HinWaei/fix4
Fixed an error
2021-11-17 09:33:48 -08:00
Eng Zer Jun 1645759742
refactor: move from io/ioutil to io and os packages
The io/ioutil package has been deprecated as of Go 1.16, see
https://golang.org/doc/go1.16#ioutil. This commit replaces the existing
io/ioutil functions with their new definitions in io and os packages.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2021-11-17 11:39:11 +08:00
Eng Zer Jun da8beb65bf
build: upgrade to Go 1.17
Go 1.17 introduces compiler improvement
(https://golang.org/doc/go1.17#compiler) and supports module graph
pruning (https://golang.org/ref/mod#graph-pruning) and lazy module
loading (https://golang.org/ref/mod#lazy-loading).

This commit applies the changes by running `go mod tidy -go=1.17` to
enable module graph pruning and lazy module loading supported by Go 1.17
or higher.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2021-11-17 11:39:01 +08:00
Hinux Chau d30433658b
Fixed an error
Fixed an error caused by nonexistence of the directory /etc/bash_completion.d/croc
2021-10-27 22:21:31 +08:00
Marcel Battista d372fa1fa4 fix panic on single digit throttles values 2021-10-19 13:10:43 +02:00
Marcel Battista 8ff3fb9b89 added throttle upload feature 2021-10-19 02:46:54 +02:00
Zack 696479024e
Update ci.yml 2021-10-08 09:43:30 -07:00
Zack 9dfa0284fa update with setup 2021-10-08 09:39:20 -07:00
Zack Scholl a12f374aba can't use the github ci 8084 2021-10-04 08:02:27 -07:00
Zack 8ee1825f84
Merge pull request #424 from jolheiser/fix-const
Fix TCP constant
2021-10-04 07:29:27 -07:00
Zack f99c33d794
Merge pull request #426 from maximbaz/ci
Run tests via Github Actions
2021-10-04 07:26:53 -07:00
Maxim Baz 417b371454
Add CI 2021-10-04 00:16:49 +02:00
jolheiser 2ffb20201c
Fix TCP constant
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2021-10-03 16:23:29 -05:00
Zack Scholl 89efd38c10 bump 9.4.2 2021-10-02 12:38:32 -07:00
Zack Scholl 49f50a53d5 need to listen on all ports 2021-10-02 12:37:16 -07:00
Zack Scholl 5d9afe03ef bump 9.4.1 2021-10-02 12:29:05 -07:00
Zack Scholl 1637765aad debugging 2021-10-02 12:23:36 -07:00
Zack Scholl ce628ea604 debugging 2021-10-02 12:20:18 -07:00
Zack Scholl ff4307c3c6 debugging 2021-10-02 12:18:50 -07:00
Zack Scholl e5f59fa0f9 fix local 2021-10-02 12:02:25 -07:00
Zack Scholl 04662df347 fix local 2021-10-02 11:55:43 -07:00
Zack Scholl 4ea66fbd18 upgrade peerdiscovery 2021-10-02 10:55:12 -07:00
Zack Scholl d96c98f4ce bump 9.4.0 2021-10-02 10:45:00 -07:00
Zack Scholl 31db6a76e5 bump 9.4.0 2021-10-02 10:44:48 -07:00
Zack Scholl a996f3c4f4 bump 9.4.0 2021-10-02 10:44:34 -07:00
Zack Scholl 4334c870f5 bump 9.4.0 2021-10-02 10:44:17 -07:00
Zack Scholl 2b1367a09b bump 9.4.0 2021-10-02 10:44:05 -07:00
Zack Scholl add1650cbd bump 9.4.0 2021-10-02 10:43:14 -07:00
Zack Scholl 04f2dfac97 bump 9.4.0 2021-10-02 10:41:46 -07:00
Zack Scholl 060ce516b1 bump 9.4.0 2021-10-02 10:41:26 -07:00
Zack Scholl 78b6f2d858 update deps 2021-10-02 10:37:20 -07:00
Zack d77c83ce09
Merge pull request #419 from kallydev/patch
Add host flag for relay
2021-10-02 10:35:00 -07:00
Zack a34d29befc
Merge pull request #420 from jolheiser/const
Constants and Message Types
2021-10-02 10:33:52 -07:00
Zack 914d0c98a8
Merge pull request #421 from jolheiser/wildcard
Add wildcard support for files
2021-10-02 10:33:15 -07:00
Zack 55cb35d12b
Merge pull request #422 from BrandonIngalls/gh-405-config-defaults
Do not override defaults with empty values
2021-10-02 10:29:40 -07:00
Brandon Ingalls 860a75fee6 Do not override defaults with empty values
This change will make it so a user who used the -remember
option on an older version of the application will be able
to use the latest version of the software without deleting
their saved config.

fixes schollz/croc#405
relates to schollz/croc#417
2021-10-02 11:12:34 -05:00
jolheiser e380c7b1f1
Add wildcard support
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2021-10-01 16:49:21 -05:00
jolheiser 2381f26c61
Move to consts and "enum"
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2021-10-01 16:24:28 -05:00
KallyDev de454bbf5a
add host flag for relay 2021-10-01 12:55:28 +08:00
Zack Scholl e19e06a652 update deps 2021-09-14 10:44:33 -07:00
Zack 6deafaadae
Merge pull request #412 from adworacz/sendMultifileDocs
Clarify croc's ability to send multiple files/folder
2021-08-29 10:51:04 -07:00
Austin Dworaczyk Wiltshire ef3953a586 Clarify croc's ability to send multiple files/folder
I was personally shocked that I could send multiple files via croc
recently, having done it purely on a whim. The existing CLI
documentation makes no mention of croc's ability to send multiple
files/folders.

This adds it.
2021-08-29 10:16:51 -07:00
Zack Scholl 1d3fdffed6 bump 9.3.0 2021-08-16 12:29:43 -07:00
Zack Scholl 94b2aff637 update deps 2021-08-16 12:28:26 -07:00
Zack 9ce2321d01
Merge pull request #409 from CHTJonas/master
Make internal DNS resolution opt-in
2021-08-16 12:27:57 -07:00
Charlie Jonas d75530b78b Improve built-in list of public DNS recursors 2021-08-16 18:48:03 +01:00
Charlie Jonas f64f68d5a9 Tidy up code slightly 2021-08-16 18:47:25 +01:00
Charlie Jonas be7705efc3 Remove DNS lookup timeouts 2021-08-16 18:32:55 +01:00
Charlie Jonas df2e29b74d Add --internal-dns flag 2021-08-16 18:25:34 +01:00
Zack Scholl b73fdff702 mv goreleaser 2021-08-06 14:35:53 -07:00
Zack Scholl 664936feb2 bump 9.2.1 2021-08-06 13:46:23 -07:00
Zack Scholl 4b1eb6519c update deps 2021-08-06 13:45:23 -07:00
Zack Scholl 86aeed93db move mutex to avoid race condition #407 2021-08-06 09:48:26 -07:00
Zack Scholl 7993e73ac2 update deps 2021-07-29 13:43:21 -07:00
Zack Scholl d922808fd8 change install cmd 2021-06-25 13:19:23 -07:00
Zack Scholl 8d22737fd3 bump 9.2.0 2021-06-21 11:54:11 -07:00
Zack Scholl d442755814 show preparing progress 2021-06-21 11:11:44 -07:00
Zack Scholl 0afdf71305 update deps 2021-06-21 07:43:20 -07:00
Zack Scholl ecf3eb872e allow selecting hash 2021-06-21 07:34:28 -07:00
Zack Scholl 646c879edc bump 9.1.6 2021-06-15 15:08:32 -07:00
Zack Scholl cbe9cbe32a update deps 2021-06-15 14:54:22 -07:00
Zack Scholl 4796404b7e show resume message if resuming
Fixes #402
2021-06-15 14:53:16 -07:00
Zack Scholl 3e2c88c5bc bump 9.1.5 2021-06-10 14:45:24 -07:00
Zack Scholl 0124356cd7 update deps 2021-06-10 14:44:49 -07:00
Zack f2ef6f19a5
Merge pull request #401 from nikoksr/refactor/accept-enter-in-prompts
refactor: Accept enter in prompts
2021-06-10 14:43:11 -07:00
Niko Köser 5e0d6522b0
refactor: accept enter in user prompts
Until now, the process of receiving a file was aborted when an
empty entry (Enter) was made. It is common under *nix that
pressing Enter without prior input of other characters selects
the default answer. This would also make the process more
fluid for croc.

In most usecases the default choice will be 'Y'/'Yes'. The only
exception is the prompt for overwriting existing files. We default
to 'N'/'No' in this prompt to prevent accidental overwriting of
files.
2021-06-10 14:12:05 +02:00
Niko Köser c72aaf63cb
chore(git): ignore .idea and .vscode folders 2021-06-09 16:00:09 +02:00
Zack Scholl a9e77673f4 update deps 2021-05-12 12:04:30 -07:00
Zack Scholl aa93d3e30f Merge branch 'master' of github.com:schollz/croc 2021-05-12 07:19:09 -07:00
Zack Scholl 15a19e1998 use all the config options 2021-05-12 07:19:02 -07:00
Zack Scholl e1ccb58d8f bump 9.1.4 2021-05-12 07:04:38 -07:00
Zack Scholl d0ebb7ad38 longer time for local connections 2021-05-12 07:04:10 -07:00
Zack Scholl 2bfbacf972 bump 9.1.3 2021-05-11 10:06:14 -07:00
Zack Scholl e29b4c47fd update deps 2021-05-11 10:05:37 -07:00
Zack Scholl b4deedf367 upgrade peerdiscovery 2021-05-11 10:04:21 -07:00
Zack Scholl 68e507dbba update peerdiscovery 2021-05-11 07:09:56 -07:00
Zack Scholl 66f30c0565 skip autocomplete installation on fish, Fixes #393 2021-05-10 13:47:17 -07:00
Zack Scholl 340bafba3d bump 9.1.2 2021-05-07 10:23:45 -07:00
Zack Scholl e47776bb10 fix 2021-05-07 10:21:24 -07:00
Zack 422f099e5e
Merge pull request #390 from wamserma/patch-1
Distinguish text message from file in receipient dialog
2021-05-07 10:20:53 -07:00
Zack Scholl bd4886ae3c update deps 2021-05-07 10:18:40 -07:00
Markus Wamser d5fd2060dd
Distinguish text message from file in receipient dialog
Fixes https://github.com/schollz/croc/issues/388
2021-05-01 21:27:44 +02:00
Zack Scholl 7c28279a58 bump 9.1.1 2021-04-29 09:43:50 -07:00
Zack Scholl 27b7cdbf12 bug fix: doesn't ask overwrite text Fixes #384 2021-04-29 09:16:22 -07:00
Zack Scholl 24fb8746a4 fix deadlock 2021-04-29 09:11:29 -07:00
Zack 45cb545a82
Merge pull request #383 from oxzi/dns-prefer-local
Prefer local DNS resolver over public DNS servers
Fixes #301
2021-04-26 10:45:07 -07:00
Alvar Penning 8f5c73837a Prefer local DNS resolver over public DNS servers
The changes cause the local DNS resolver to be used exclusively at
first. If this fails, the public DNS servers are queried as before.

This feature was previously requested. Merging should close #301.

Along the way, three other changes are introduced:

1. A public IPv6 DNS server was added.

2. The lookup returns the first result from a public DNS server and does
   not wait for all queries to be answered.

3. In the unlikely case that no public DNS server is able to answer, an
   error will be returned.
2021-04-26 11:43:45 +02:00
Zack b90f9329ca
Merge pull request #376 from Craeckie/master
Use unprivileged user in docker
2021-04-23 10:28:22 -07:00
Craeckie 968950f783
Use unprivileged user in docker
See 
https://americanexpress.io/do-not-run-dockerized-applications-as-root/
and 
https://engineering.bitnami.com/articles/why-non-root-containers-are-important-for-security.html
2021-04-22 09:53:49 +00:00
Zack Scholl 5b0883e1fe generate key once 2021-04-21 16:57:18 -07:00
Zack Scholl 420030998f add chacha20 2021-04-21 16:53:29 -07:00
Zack Scholl de2bcf114c upgrade imohash 2021-04-21 14:36:50 -07:00
Zack Scholl ab5ae5cbb6 add more benchmarks 2021-04-21 12:40:41 -07:00
Zack Scholl 94b3dba034 update readme 2021-04-20 16:01:44 -07:00
Zack 1a47543be9
Merge pull request #344 from k3b/patch-1
Added reference to croc android-version to README.md
2021-04-20 15:59:44 -07:00
Zack Scholl 407e162ec2 bump 9.1.0 2021-04-20 15:57:46 -07:00
Zack 35106d4dbe
Merge pull request #374 from schollz/v91
V91
2021-04-20 15:55:19 -07:00
Zack Scholl d6af319ad8 fix tests 2021-04-20 15:48:13 -07:00
Zack Scholl 85e7576311 fix 2021-04-20 15:44:28 -07:00
Zack Scholl 7ac7be37af check if file exists 2021-04-20 15:36:46 -07:00
Zack Scholl 669aeb377a check if file exists 2021-04-20 15:35:38 -07:00
Zack Scholl b655afb533 choose hash algorithm 2021-04-20 15:32:05 -07:00
Zack Scholl e9949ce3d7 check file size firsty 2021-04-20 09:08:02 -07:00
Zack Scholl 91a3dd5866 Merge branch 'master' of github.com:schollz/croc 2021-04-17 20:42:20 -07:00
Zack Scholl 026487a833 update docker 2021-04-17 20:40:56 -07:00
Zack Scholl f8ef096784 bump 9.0.0 2021-04-17 20:33:18 -07:00
Zack Scholl 0c2089bd4c update deps 2021-04-17 20:32:55 -07:00
Zack Scholl 5ad68b9ced update readme 2021-04-17 20:31:17 -07:00
Zack Scholl 9286b3c965 show folders when receiving 2021-04-17 20:27:51 -07:00
Zack Scholl c1edf24338 fix race condition 2021-04-17 20:07:50 -07:00
Zack Scholl d38fc18390 update deps 2021-04-17 14:31:32 -07:00
Zack Scholl f4cedd1e91 Merge branch 'master' of github.com:schollz/croc 2021-04-17 11:27:25 -07:00
Zack Scholl fc66c3b91f improve readme 2021-04-17 11:27:20 -07:00
Zack Scholl 2ac7d4f31f fix tests 2021-04-17 11:12:15 -07:00
Zack Scholl a96762b942 fix room deletion if room is full 2021-04-17 10:44:10 -07:00
Zack Scholl 0a0f7a03d7 update version 2021-04-17 10:33:38 -07:00
Zack Scholl 8148e191ae bump 2021-04-17 17:31:44 +00:00
Zack Scholl 25a985464a Merge branch 'master' of github.com:schollz/croc 2021-04-17 17:15:02 +00:00
Zack 333ece706e
Merge pull request #369 from schollz/v9
V9
2021-04-17 10:12:42 -07:00
Zack Scholl daf10395a3 update deps 2021-04-17 09:42:11 -07:00
Zack Scholl 9231b1a661 update utils benchmark 2021-04-17 09:39:47 -07:00
Zack Scholl 3e56d4cdb9 use magic bytes instead of checking max 2021-04-17 09:05:27 -07:00
Zack Scholl cec39ba2ce allow changing curve 2021-04-17 09:01:58 -07:00
Zack Scholl 7a997156ed minor 2021-04-16 17:17:32 -07:00
Zack Scholl c02b4f1256 fix: make sure that only pake messages are unencrypted 2021-04-16 17:15:51 -07:00
Zack Scholl babfd5f35f add option to overwrite automatically 2021-04-16 15:14:21 -07:00
Zack Scholl be5ceae8c7 prompt to overwrite 2021-04-16 15:12:11 -07:00
Zack Scholl 6be4080f05 remove hash exchange 2021-04-16 14:25:57 -07:00
Zack Scholl b0693751c1 fix 2021-04-16 14:01:48 -07:00
Zack Scholl 8250a39534 fix: delete room if full and third-party tries to enter 2021-04-16 09:48:11 -07:00
Zack Scholl 2131e99826 use new pake 2021-04-16 09:20:13 -07:00
Zack Scholl 628043b228 fix: do not use part of secret as room name 2021-04-16 08:13:43 -07:00
Zack Scholl 362a30e5e7 Merge branch 'master' of github.com:schollz/croc 2021-04-15 22:05:04 +00:00
Zack 828de41d6c
Merge pull request #361 from tdussa/BrokenSymlink
Transfer symlinks without touching their targets.
2021-04-15 15:01:49 -07:00
Tobias Dussa 876ce5764b Transfer symlinks without touching their targets. 2021-04-15 17:07:23 +02:00
Zack Scholl 59b287df7f Merge branch 'master' of github.com:schollz/croc 2021-04-13 22:40:03 +00:00
Zack 3fd125178f
Merge pull request #341 from MatejKafka/master
Added CROC_CONFIG_DIR env var to support custom config dir path
2021-04-13 15:38:38 -07:00
Zack 136faac448
Merge pull request #355 from stingalleman/patch-1
Remove dollar icons from commands without output
2021-04-13 15:37:22 -07:00
Zack 85a0bfb898
Merge pull request #359 from mizzunet/patch-1
Enhancements to bug_report.md
2021-04-13 15:36:39 -07:00
Missu 4718f3897c
Commented, added bug label
Commented lines need to be manually removed by the user, so no need to remove those anymore
Added "big" label for this, so easily discoverable from the Issues list
2021-04-08 11:42:19 +05:30
Sting Alleman 068d5c1031
Remove dollar icons from commands without output 2021-04-04 22:57:14 +02:00
Zack Scholl 4dfa1a9236 Merge branch 'master' of github.com:schollz/croc 2021-03-26 23:05:01 +00:00
Zack Scholl 6ba6ec9d32 bump 8.6.12 2021-03-26 16:03:51 -07:00
Zack Scholl c373b38b59 bump 8.6.12 2021-03-26 16:03:31 -07:00
Zack Scholl f2af5b7256 don't know why , but won't compile for freebsd/arm
⨯ release failed after 348.00s error=failed to build for freebsd_arm_7: # golang.org/x/net/ipv4
../../../../pkg/mod/golang.org/x/net@v0.0.0-20210326220855-61e056675ecf/ipv4/sys_freebsd.go:37:79: undefined: unix.MCAST_JOIN_GROUP
../../../../pkg/mod/golang.org/x/net@v0.0.0-20210326220855-61e056675ecf/ipv4/sys_freebsd.go:38:79: undefined: unix.MCAST_LEAVE_GROUP
../../../../pkg/mod/golang.org/x/net@v0.0.0-20210326220855-61e056675ecf/ipv4/sys_freebsd.go:39:79: undefined: unix.MCAST_JOIN_SOURCE_GROUP
../../../../pkg/mod/golang.org/x/net@v0.0.0-20210326220855-61e056675ecf/ipv4/sys_freebsd.go:40:79: undefined: unix.MCAST_LEAVE_SOURCE_GROUP
../../../../pkg/mod/golang.org/x/net@v0.0.0-20210326220855-61e056675ecf/ipv4/sys_freebsd.go:41:79: undefined: unix.MCAST_BLOCK_SOURCE
../../../../pkg/mod/golang.org/x/net@v0.0.0-20210326220855-61e056675ecf/ipv4/sys_freebsd.go:42:79: undefined: unix.MCAST_UNBLOCK_SOURCE
2021-03-26 16:02:39 -07:00
Zack Scholl 483f840401 Merge branch 'master' of github.com:schollz/croc 2021-03-26 22:45:03 +00:00
Zack Scholl ff12c33e7f bump 8.6.12 2021-03-26 15:41:45 -07:00
Zack Scholl e4cecf670b update deps 2021-03-26 15:41:13 -07:00
Zack Scholl 94e0e3ca67 Merge branch 'master' of github.com:schollz/croc 2021-03-26 22:40:03 +00:00
Zack Scholl a9d582cc6a lookup using standard dns 2021-03-26 15:39:33 -07:00
k3b ab9396937c
Added reference to croc android-version to README.md
See https://f-droid.org/en/packages/com.github.howeyc.crocgui/ for details
2021-03-25 12:32:17 +01:00
Matej Kafka c1e546ede6
Added CROC_CONFIG_DIR env var to support custom config dir path 2021-03-20 00:50:50 +01:00
Zack Scholl 63ba28c9b0 Merge branch 'master' of github.com:schollz/croc 2021-03-17 17:20:04 +00:00
Zack 6caf72df82
Merge pull request #340 from jfaltis/xdg-basedir-spec-compliance
Add compliance with XDG Base Directory Specification (XDG_CONFIG_HOME)
2021-03-17 10:17:52 -07:00
Jona 2273438373 add compliance with xdg base directory specification in regards to XDG_CONFIG_HOME 2021-03-17 17:45:07 +01:00
Zack Scholl 50a0d86e3d Merge branch 'master' of github.com:schollz/croc 2021-03-15 19:40:02 +00:00
Zack Scholl 50aa24d86d bump 8.6.11 2021-03-15 12:39:04 -07:00
Zack Scholl 674bff7a13 Merge branch 'master' of github.com:schollz/croc 2021-03-15 19:35:03 +00:00
Zack Scholl 757ed180fb update deps 2021-03-15 12:31:07 -07:00
Zack Scholl 76648a2926 Merge branch 'master' of github.com:schollz/croc 2021-03-15 19:05:04 +00:00
Zack Scholl 0b76edc362 update deps 2021-03-15 12:04:48 -07:00
Zack Scholl c39061c7fc Merge branch 'master' of github.com:schollz/croc 2021-03-15 18:55:03 +00:00
Zack Scholl fb2723d80b don't show description if only sending one file 2021-03-15 11:50:30 -07:00
Zack Scholl f84341a197 Merge branch 'master' of github.com:schollz/croc 2021-03-10 16:20:03 +00:00
Zack 6e9156d49c
Merge pull request #337 from alrs/alrs-fix-server-nil-salt-and-keys
src/tcp: fix dropped errors
2021-03-10 08:16:19 -08:00
Zack cd6d9a5aa0
Merge pull request #338 from alrs/alrs-fix-client-swallowed-errs
src/croc: fix dropped errors
2021-03-10 08:16:06 -08:00
Lars Lehtonen 3e5b876a32
src/croc: fix dropped errors 2021-03-09 16:55:42 -08:00
Lars Lehtonen a9487a332c
src/tcp: fix dropped errors 2021-03-09 16:48:38 -08:00
Zack Scholl de924f6a4f Merge branch 'master' of github.com:schollz/croc 2021-03-08 16:45:04 +00:00
Zack Scholl 03a27b6683 bump 8.6.10 2021-03-08 08:41:54 -08:00
Zack Scholl 0b719b9b77 update deps 2021-03-08 08:41:17 -08:00
Zack Scholl fc34d21cb8 thanks 2021-03-08 08:41:00 -08:00
Zack Scholl bb05d48fe9 Merge branch 'master' of github.com:schollz/croc 2021-03-08 16:40:02 +00:00
Zack 949480517f
Merge pull request #336 from hreese/master
Added support for SOCKS5 authentication (fixes #333)
2021-03-08 08:38:27 -08:00
Heiko Reese a20ebd7120 Added support for SOCKS5 authentication (fixes #333) 2021-03-06 11:55:16 +01:00
Zack Scholl d49bb8632b Merge branch 'master' of github.com:schollz/croc 2021-03-05 19:05:02 +00:00
Zack Scholl 10e57c3f97 bump 8.6.9 2021-03-05 11:02:51 -08:00
Zack Scholl be95662e35 update deps 2021-03-05 11:01:51 -08:00
Zack Scholl 105fb9a3ce Merge branch 'master' of github.com:schollz/croc 2021-03-05 17:05:02 +00:00
Zack Scholl 30783ce79c overwrite symlinks on transfer, like files, fixes #334 2021-03-05 09:00:15 -08:00
Zack Scholl a46f09ee1c Merge branch 'master' of github.com:schollz/croc 2021-02-23 20:15:02 +00:00
Zack Scholl cdabf629b6 bump 8.6.8 2021-02-23 12:10:30 -08:00
Zack Scholl 40cda1bed7 Merge branch 'master' of github.com:schollz/croc 2021-02-23 20:10:04 +00:00
Zack Scholl 92ab62d03e bump 8.6.8 2021-02-23 12:09:50 -08:00
Zack Scholl 31012b8f7d fix goreleaser 2021-02-23 12:09:42 -08:00
Zack Scholl 4b0d01d8f0 bump 8.6.8 2021-02-23 12:06:59 -08:00
Zack Scholl 648eb6c71d update deps 2021-02-23 12:03:29 -08:00
Zack Scholl b19a028aea Merge branch 'master' of github.com:schollz/croc 2021-02-19 18:30:03 +00:00
Zack 9588f2b4a4
Merge pull request #331 from schollz/dns
Dns
2021-02-19 10:25:32 -08:00
Zack Scholl cd2802b8b5 shorter dns fail time 2021-02-19 10:18:13 -08:00
Zack Scholl c5ff55a193 find dns from any number of providers 2021-02-19 10:16:58 -08:00
Zack Scholl 1cf309faf2 Merge branch 'master' of github.com:schollz/croc 2021-02-11 22:10:05 +00:00
Zack 8dc5bd6e04
Merge pull request #328 from lekoOwO/patch-1
Add alpine linux installation instructions
2021-02-11 14:06:29 -08:00
leko 37f09049a4
Update README.md 2021-02-11 15:19:11 +08:00
Zack Scholl eaa18cd502 Merge branch 'master' of github.com:schollz/croc 2021-02-10 17:40:04 +00:00
Zack Scholl b9d461e5df update deps 2021-02-10 09:36:42 -08:00
Zack Scholl 89ea0166fa Merge branch 'master' of github.com:schollz/croc 2021-02-03 18:10:04 +00:00
Zack Scholl 77fd78e408 Merge branch 'master' of github.com:schollz/croc 2021-02-03 10:08:40 -08:00
Zack Scholl edeb7c8886 update deps 2021-02-03 10:08:30 -08:00
Zack Scholl 4481fe2336 Merge branch 'master' of github.com:schollz/croc 2021-02-02 14:50:03 +00:00
Zack ef43873c3b
Merge pull request #325 from nikoksr/fix/missing-code-too-short-error
fix(cli): make 'code too short' error symmetric on both sender and receiver side
2021-02-02 06:48:21 -08:00
Zack Scholl 0bec0b26ab Merge branch 'master' of github.com:schollz/croc 2021-02-02 14:45:04 +00:00
Zack 681c824ef4
remove snap, it just doesn't work 2021-02-02 06:43:12 -08:00
Zack Scholl 950b6f83d9 Merge branch 'master' of github.com:schollz/croc 2021-02-01 15:00:03 +00:00
Zack Scholl 7f5d704a26 change name 2021-02-01 06:58:27 -08:00
Zack a6a8ab71ce
Merge pull request #315 from PeterEve/master
Added an option to ignore attached stdin.
2021-02-01 06:56:45 -08:00
Zack de56d2f6dd
Merge pull request #321 from Spaceface16518/docker-min
Reduce size of Docker image by stripping debug symbols
2021-02-01 06:55:08 -08:00
Zack Scholl 2f96b77b73 Merge branch 'master' of github.com:schollz/croc 2021-02-01 14:55:02 +00:00
Zack 0548c2e45f
Merge pull request #322 from benjamin-wen/patch-1
Update year
2021-02-01 06:54:42 -08:00
Niko Köser 0b60fef246
refactor: write errors into stderr and add exit code
Instead of writing errors into stdout and alway returning exit code 0,
we now write into stderr and return exit code 1 in case that an error
occured.
2021-02-01 10:48:34 +01:00
Niko Köser 3ccd4d07e9
fix: accidentally overwritten error value
In function _cli.send_ the named return value 'err' gets accidentally
overwritten in the deferred anonymous function that removes the
files/directories. Renamed the error variable inside the deferred
function so that it does not overwrite the original error anymore.

Closes #296
2021-02-01 10:34:06 +01:00
Benjamin Wen b5f1b35213
Update year 2021-01-28 11:27:27 +08:00
Spaceface16518 90eda5639f Strip go binary in docker build 2021-01-27 12:30:45 -06:00
Zack Scholl 77d0c7ae2e Merge branch 'master' of github.com:schollz/croc 2021-01-26 21:20:03 +00:00
Zack 493eb075f1
Merge pull request #318 from Spaceface16518/master
Docker deployment configuration
2021-01-26 13:16:23 -08:00
Spaceface16518 247d2b18ec Remove linux/ppc64le platform
gcc not found in $PATH?
2021-01-22 00:00:20 -06:00
Spaceface16518 6b8a14d831 Remove linux/s390x platform
Breaking the docker buildx build due to some signature verification
error
2021-01-22 00:00:20 -06:00
Amrit 743b2c1bf4
Create deploy.yml 2021-01-21 23:32:51 -06:00
Peter 17f3df7e36 Added an option to ignore attached stdin, for compatibility with node child_process 2021-01-10 13:17:43 +00:00
Zack Scholl dab683c9dc Merge branch 'master' of github.com:schollz/croc 2020-12-29 17:35:03 +00:00
Zack e829ca0ff4
thank you digital ocean 2020-12-29 09:34:57 -08:00
Zack Scholl e27c32cf6e Merge branch 'master' of github.com:schollz/croc 2020-12-28 19:05:03 +00:00
Zack Scholl a2b243ad94 bump 8.6.7 2020-12-28 11:01:27 -08:00
Zack Scholl 05640cd49f update deps 2020-12-28 11:00:44 -08:00
Zack Scholl 037dbbd4e9 Merge branch 'master' of github.com:schollz/croc 2020-12-28 18:50:06 +00:00
Zack 0994e4eda5
Merge pull request #307 from hillmarcus/306-file-size
Issue #306, File Size Mismatch
2020-12-28 10:46:39 -08:00
Zack 235f065a9c
Merge pull request #310 from vzlcn0/master
add new cmd option to set sender ip
2020-12-28 10:46:14 -08:00
vzlcn0 52bc6312e1 add new cmd option to set sender ip 2020-12-17 18:37:48 +03:00
Marcus d735cca970 Issue #306, File Size Mismatch
Updated utils.go to use a `1024` grouping instead of `1000` for file
sizes. This brings it inline with the progress bar project being used.

Updated utils_test.go to match the changes to utils.go
2020-12-07 18:44:12 -06:00
Zack Scholl af5ba6ead8 Merge branch 'master' of github.com:schollz/croc 2020-11-18 00:15:04 +00:00
Zack Scholl 5978896936 bump 8.6.6 2020-11-17 16:10:57 -08:00
Zack Scholl 2ffafd4607 Merge branch 'master' of github.com:schollz/croc 2020-11-18 00:10:04 +00:00
Zack Scholl e7ed4fc05f update deps 2020-11-17 16:09:29 -08:00
Zack Scholl 1da2f58a53 faster dns resolution on startup 2020-11-17 10:46:49 -08:00
Zack Scholl 284af7fc7a hm 2020-11-17 10:35:57 -08:00
Zack Scholl dbc4a08ad0 use google for lookup 2020-11-17 10:29:52 -08:00
Zack Scholl c55e9be0ef Merge branch 'master' of github.com:schollz/croc 2020-10-23 15:30:05 +00:00
Zack Scholl b740e491e6 bump 8.6.5 2020-10-23 08:26:15 -07:00
Zack Scholl 10ed62cfd5 Merge branch 'master' of github.com:schollz/croc 2020-10-23 15:05:03 +00:00
Zack Scholl 8d430b6cb1 update progressbar 2020-10-23 07:59:56 -07:00
Zack Scholl cdb1981358 Merge branch 'master' of github.com:schollz/croc 2020-10-23 00:05:04 +00:00
Zack Scholl f51ea8bfdc show progress 2020-10-22 17:03:46 -07:00
Zack Scholl a45e66733b Merge branch 'master' of github.com:schollz/croc 2020-10-22 17:20:05 +00:00
Zack Scholl 23f97c61ac bump 8.6.4 2020-10-22 10:18:40 -07:00
Zack Scholl cbb728b9a2 bump 8.6.4 2020-10-22 10:17:58 -07:00
Zack Scholl 9bb2d2b7cc bump 8.6.4 2020-10-22 10:17:33 -07:00
Zack Scholl 3f10a147dd bump 8.6.4 2020-10-22 10:16:55 -07:00
Zack Scholl d112f43f63 Merge branch 'master' of github.com:schollz/croc 2020-10-22 17:15:04 +00:00
Zack Scholl bf9ebfc4b4 show ping 2020-10-22 10:13:41 -07:00
Zack Scholl d3aa2be9ab ping server from discoveries 2020-10-22 10:11:11 -07:00
Zack Scholl 034e012227 allow pinging 2020-10-22 10:09:04 -07:00
Zack Scholl 05c82809c6 Merge branch 'master' of github.com:schollz/croc 2020-10-22 17:05:04 +00:00
Zack Scholl 79f85fda9b bug fix: return if found error 2020-10-22 09:59:55 -07:00
Zack Scholl 6ad8e08b0c Merge branch 'master' of github.com:schollz/croc 2020-10-22 16:55:03 +00:00
Zack Scholl 3bcc83a8fc gather all discoveries 2020-10-22 09:53:27 -07:00
Zack Scholl 6c86188564 Merge branch 'master' of github.com:schollz/croc 2020-10-22 14:45:05 +00:00
Zack Scholl 1d9393d39b bump 8.6.3 2020-10-22 07:40:56 -07:00
Zack Scholl 4663df1059 Merge branch 'master' of github.com:schollz/croc 2020-10-22 14:40:04 +00:00
Zack 817e0b78f6
Merge pull request #293 from nkhang/features/show-passphrase-issue
fix(cli): show passphrase when user indicate --pass
2020-10-22 07:40:01 -07:00
Khang. Nguyen Khac Nguyen 4070f12cbf change(croc): shorten flag with builder 2020-10-22 14:06:54 +07:00
Khang. Nguyen Khac Nguyen 8e50b59671 fix(cli): show passphrase when user indicate --pass
+ when user indicate --pass when sending file, indicate --pass flag in
recommended receive command.
2020-10-22 13:37:32 +07:00
Zack Scholl 61ffdc61f3 Merge branch 'master' of github.com:schollz/croc 2020-10-21 19:55:03 +00:00
Zack Scholl ff45ccd346 bump 8.6.2 2020-10-21 12:52:53 -07:00
Zack Scholl 5a791e98af bump 8.6.2 2020-10-21 12:51:47 -07:00
Zack Scholl 0d767af80a fix makefile 2020-10-21 12:51:43 -07:00
Zack Scholl bb971a9937 bump 8.6.1 2020-10-21 12:50:30 -07:00
Zack Scholl c88d3ad62a update makefile 2020-10-21 12:50:25 -07:00
Zack Scholl 1a242711cc Merge branch 'master' of github.com:schollz/croc 2020-10-21 17:30:05 +00:00
Zack Scholl 77732c49a0 bump 8.6.0 2020-10-21 10:28:28 -07:00
Zack Scholl b9b22ad041 bump 8.6.0 2020-10-21 10:28:27 -07:00
Zack Scholl 7a73e4912c allow using only local with --local flag 2020-10-21 18:25:56 +01:00
Zack Scholl 3129b097af use only local 2020-10-21 10:23:12 -07:00
Zack Scholl 1967ef57be bump 8.5.3 2020-10-21 09:41:08 -07:00
Zack Scholl b95c2c781b bump 8.5.3 2020-10-21 09:41:07 -07:00
Zack Scholl ea0e334feb add back ipv6 broadcast 2020-10-21 08:17:39 -07:00
Zack de03a5167a
Merge pull request #292 from nkhang/chore/cleanup
cleanup: cleanup dependencies and remove unused code
2020-10-21 08:16:52 -07:00
Khang. Nguyen Khac Nguyen 12e09020d1 chore(mod): cleanup dependencies
+ cleanup dependencies since we do not use spinner anymore.
2020-10-21 15:56:28 +07:00
Khang. Nguyen Khac Nguyen e85ac9f8bf chore(croc): remove redundant code
+ remove redundant return of func that does not return
+ remove func that is not used
2020-10-21 15:52:04 +07:00
Khang. Nguyen Khac Nguyen 9f54f2d08f chore(comm): cleanup comm Write func
+ better handling error.
+ use Send instead of Write since we do not need number of bytes sent.
2020-10-21 15:16:42 +07:00
Zack Scholl f5624007c8 bump 8.5.2 2020-10-19 11:04:43 -07:00
Zack Scholl 9b6c33c300 bump 8.5.2 2020-10-19 11:04:42 -07:00
Zack Scholl b66cfb4cc1 disable ipv6 for peer-to-peer discovery since it causes issues 2020-10-19 11:02:48 -07:00
Zack Scholl a5bcf382e0 update deps 2020-10-19 09:45:49 -07:00
Zack Scholl 539d66806a bump 8.5.1 2020-10-13 15:48:43 -07:00
Zack Scholl 768f3e1318 bump 8.5.1 2020-10-13 15:48:43 -07:00
Zack Scholl a968f494fa better help 2020-10-13 15:47:53 -07:00
Zack Scholl 911bb22b2d better environmental variable 2020-10-13 15:47:00 -07:00
Zack Scholl 58796824bb update deps 2020-10-13 15:45:54 -07:00
Zack Scholl f3697f6aad reduce packets sent for peer discovery 2020-10-13 13:47:43 -07:00
Zack Scholl 5374be1a0f use dns to determine relay 2020-10-13 12:26:11 -07:00
Zack Scholl 1d874b5dbe bump 8.5.0 2020-10-12 12:34:47 -07:00
Zack Scholl 586fc08768 bump 8.5.0 2020-10-12 12:34:47 -07:00
Zack Scholl fa1359f1b8 dos2unix 2020-10-12 12:33:56 -07:00
Zack Scholl b12fc47951 update deps 2020-10-12 12:31:54 -07:00
Zack 5a2d51c060
bash continues if autocompletion fails to install
Fixes #286
2020-10-09 07:16:17 -07:00
Zack 3396743d73
allow proxying connection (#283) 2020-10-05 08:30:45 -07:00
Zack Scholl e75b75164f bump 8.4.0 2020-10-04 13:16:36 -07:00
Zack Scholl 224c442567 bump 8.4.0 2020-10-04 13:16:35 -07:00
Zack 669920d4b5
Merge pull request #281 from TheQueasle/253-autocomplete-install
First pass at adding in the autocomplete files to the installer script
2020-10-04 13:12:04 -07:00
Zack 626490545a
Merge pull request #280 from fooofei/bug/review
CodeReview: fix resource leak && shorter code
2020-10-04 08:09:06 -07:00
fooofei 5a0ec9431f fix resource leak of *os.File 2020-10-04 10:38:30 +08:00
fooofei bc8c5db898 fix possible panic of nil compressor 2020-10-04 10:38:04 +08:00
fooofei c877497cc9 user io.ReadFull for shorter connection read code 2020-10-04 10:37:36 +08:00
Micheal Quinn 4675976f08 First pass at adding in the autocomplete files to the installer script 2020-09-29 22:19:10 -05:00
Zack f484635321
Merge pull request #276 from 0mp/patch-1
Add FreeBSD installation instructions
2020-09-26 05:39:05 -07:00
Mateusz Piotrowski d0f3bad818
Add FreeBSD installation instructions 2020-09-26 13:01:29 +02:00
Zack 4e6efc2678
Merge pull request #273 from abdulniyaspm/typo-fix
Fixed a typo in cli.go
2020-09-23 05:33:23 -07:00
ABDUL NIYAS P M 4ce170e73d
Fix a typo in cli.go 2020-09-23 16:28:00 +05:30
Zack 04e92a4ccd
Merge pull request #271 from tuxuser/readme/gentoo_portage
README: Add install instructions for gentoo via portage
2020-09-21 06:12:51 -07:00
Zack Scholl 43d2ff0a09 find open ports to open local relay 2020-09-21 06:02:13 -07:00
Zack Scholl 78e4d5e179 add util to find open ports 2020-09-21 05:51:50 -07:00
tuxuser 3d0b5b9d34 README: Add install instructions for gentoo via portage 2020-09-21 03:16:15 +02:00
Zack dab52b4af7
Merge pull request #268 from theStack/fix_send_without_argument
fix send without argument (trigger intended error message)
2020-09-20 15:32:34 -07:00
Sebastian Falbesoner a313a96a8e fix send without argument (trigger intended error message) 2020-09-19 21:48:11 +02:00
Zack a507b98cbe
Merge pull request #266 from theStack/show_all_files_when_sending_without_send
Show all files when sending without send command
2020-09-19 09:35:14 -07:00
Sebastian Falbesoner 2de73cb138 show all files when sending without send command 2020-09-19 17:52:32 +02:00
Zack 20a8603ffe
Merge pull request #265 from TheChiefMeat/patch-1
Added Chocolatey installation information
2020-09-19 06:53:24 -07:00
TheChiefMeat ebe713e881
Added Chocolatey installation information 2020-09-19 12:35:35 +01:00
Zack 28c38a4b9e
doh 2020-09-18 17:07:55 -07:00
Zack 1faebcf2e2
Fixes #262 2020-09-18 17:07:41 -07:00
Zack db388f47a6
Merge pull request #263 from sa3dany/patch-1
fix typo in readme
2020-09-18 10:58:31 -07:00
sa3dany a0cc9e943b
fix typo in readme 2020-09-18 20:42:34 +03:00
Zack Scholl 9ac64f5c75 fast 2020-09-18 06:38:18 -07:00
Zack Scholl 7b15dcd2dc fork urfave/cli 2020-09-17 13:04:33 -07:00
Zack Scholl fda0bf7fd4 bump 8.3.2 2020-09-16 14:54:02 -07:00
Zack Scholl 7d155adcf1 bump 8.3.2 2020-09-16 14:54:02 -07:00
Zack Scholl ebc2cb2d03 update progressbar and peerdiscovery 2020-09-16 14:28:11 -07:00
Zack b144fa28e7
Merge pull request #260 from masterZSH/master
Use hex.EncodeToString to encode to hex
2020-09-16 11:00:09 -07:00
masterZSH f9f32a4b0e Use hex.EncodeToString to encode to hex 2020-09-16 16:37:21 +08:00
Zack Scholl b916b89f7e include files as they are 2020-09-15 12:46:42 -07:00
Zack Scholl 32bb98fd4f fix making publish 2020-09-15 12:46:07 -07:00
Zack Scholl ad6e7dff43 add autocomplete files to goreleaser 2020-09-15 12:30:53 -07:00
Zack Scholl a48bf7bbe0 hook happens in make file 2020-09-15 12:29:36 -07:00
Zack de8dfb10aa
Merge pull request #259 from masterZSH/master
Add error reporting
2020-09-15 09:23:42 -07:00
masterZSH 833668e8f2 Add error reporting 2020-09-15 09:33:43 +08:00
Zack Scholl 8a0800ca90 better error 2020-09-13 12:15:05 -07:00
Zack Scholl 4fc40274db use default bash complete 2020-09-13 12:11:18 -07:00
Zack Scholl 8c116cf66a add autocompletion 2020-09-12 08:42:19 -07:00
Zack acda80d35c
Merge pull request #254 from Naramsim/patch-1
docs(readme): shorten docker command for the relay
2020-09-09 13:18:12 -07:00
Alessandro Pezzè 1534e913a3
docs(readme): shorten docker command for the relay 2020-09-09 21:53:15 +02:00
Zack b9e834104a
Merge pull request #252 from jolheiser/env
Add environment variables to CLI
2020-09-09 09:35:07 -07:00
Zack 0aabd23c61
Merge pull request #251 from jolheiser/gitignore
Simple gitignore
2020-09-09 09:34:27 -07:00
jolheiser ccba416e85
Env vars for a few CLI options
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2020-09-09 10:25:13 -05:00
jolheiser 8258222cc5
Simple gitignore
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2020-09-09 10:22:53 -05:00
Zack f70eb17afb
Merge pull request #249 from jolheiser/cli
Update CLI to v2
2020-09-09 08:12:25 -07:00
jolheiser 5ad8bd8e2c
Fix aliases
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2020-09-09 10:06:13 -05:00
jolheiser 9a20d507a7
Update CLI to v2
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2020-09-09 10:05:57 -05:00
Zack f2c5ca820a
Merge pull request #246 from herbygillot/readme-macports
README: add instructions for installing with MacPorts
2020-09-07 22:16:38 -07:00
Herby Gillot ce7c497c09 README: add instructions for installing with MacPorts 2020-09-08 00:15:07 -04:00
Zack 1226a802e4
Merge pull request #244 from astrophena/patch-1
Add Termux installation instructions to README.md
2020-09-06 15:42:49 -07:00
Ilya Mateyko f20c42319b
Add Termux installation instructions to README.md 2020-09-07 01:03:24 +03:00
Zack Scholl a5e882ec25 bump 8.3.1 2020-09-06 08:47:32 -07:00
Zack Scholl 9d5302b1b7 bump 8.3.1 2020-09-06 08:47:31 -07:00
Zack Scholl bdb859c15c use version 2020-09-06 08:45:59 -07:00
Zack Scholl 22c35412ac bump 8.3.1 2020-09-06 08:44:04 -07:00
Zack Scholl f2af0b7ed5 bump 8.3.1 2020-09-06 08:44:03 -07:00
Zack Scholl 5d6546ba58 tag 2020-09-06 08:43:14 -07:00
Zack Scholl f4fe211bbe bump 8.3.2 2020-09-06 08:42:51 -07:00
Zack Scholl f950633a86 bump 8.3.2 2020-09-06 08:37:37 -07:00
Zack Scholl 65b6111512 push before prepare 2020-09-06 08:37:10 -07:00
Zack Scholl 2db2a914f2 bump 8.3.1 2020-09-06 08:33:14 -07:00
Zack Scholl 345ef0567e compute filename and deliver without overwriting 2020-09-05 17:23:07 -07:00
Zack 189890259e
Update README.md 2020-09-04 09:00:30 -07:00
Zack Scholl e771e20ac4 fix version 2020-09-04 06:08:38 -07:00
Zack Scholl 5e78725afa Fixes #240 2020-09-04 06:06:48 -07:00
Zack Scholl fc14ef25ed version with v 2020-09-03 15:55:52 -07:00
Zack Scholl b48c96fc37 bump 8.3.0 2020-09-03 15:51:13 -07:00
Zack Scholl 87e54acd8a add option to disable compression Fixes #239 2020-09-03 15:09:23 -07:00
Zack Scholl 555ddec5e3 handle symlinks Fix #238 2020-09-03 14:57:09 -07:00
Zack Scholl ff99b07ef1 gather symlink info 2020-09-03 14:49:08 -07:00
Zack Scholl 26056a8366 test release 2020-09-03 14:21:43 -07:00
Zack Scholl 3692e32dfb don't tag version before commiting 2020-09-03 14:19:32 -07:00
Zack Scholl 11efb6be5e get version from env varaible 2020-09-03 14:17:12 -07:00
Zack Scholl 900424ca66 update go in docker 2020-09-03 13:34:10 -07:00
Zack Scholl bd2376e920 allow getting password through file Fix #226 2020-09-03 13:31:01 -07:00
Zack Scholl def4f94ffd Merge branch 'master' of github.com:schollz/croc into master 2020-09-03 12:45:47 -07:00
Zack Scholl bbc0ce4e9c better info about incorrect passwords Fixes 237 2020-09-03 12:45:40 -07:00
Zack Scholl 8b6c0d1c39 bump 8.2.1 2020-09-03 11:40:29 -07:00
Zack Scholl d55327d344 bump 8.2.1 2020-09-03 11:40:23 -07:00
Zack Scholl c7ba55fc83 use default port of 9009 if none found #236 2020-09-03 09:53:14 -07:00
Zack Scholl 85b370291d update readme about sending text Fixes #233 2020-09-03 09:42:56 -07:00
Zack Scholl 81ad30c633 bump 8.2.0 2020-09-02 17:37:17 -07:00
Zack ba2c46c1cb
Merge pull request #234 from schollz/text
send and receive text
2020-09-02 17:36:33 -07:00
Zack Scholl 0eb095bf76 println 2020-09-02 17:35:36 -07:00
Zack Scholl 8fbb7e5019 send and receive text 2020-09-02 17:33:53 -07:00
Zack Scholl 48d63e4854 text works 2020-09-02 17:24:32 -07:00
Zack Scholl ea781e569b bug fix: propogate error when connecting 2020-09-02 09:46:31 -07:00
Zack Scholl a8c5bef7c0 raise max bytes to allow huge files #231 2020-09-01 09:32:03 -07:00
Zack Scholl b188a2691e bump 8.1.3 2020-08-31 11:58:07 -07:00
Zack Scholl 20967519fd update deps 2020-08-31 11:56:25 -07:00
Zack Scholl 09a37a2be4 update readme 2020-08-30 08:54:07 -07:00
Zack Scholl 7bc9dc1826 bump 8.1.2 2020-08-27 10:49:30 -07:00
Zack Scholl 2345148fde make sure conn is not nil 2020-08-27 10:13:47 -07:00
Zack Scholl 50bf003022 try ipv6 first 2020-08-27 09:40:41 -07:00
Zack Scholl 695444159e add default ipv6 relay 2020-08-27 09:24:19 -07:00
Zack Scholl 0533f0c96e release auto 2020-08-27 08:15:01 -07:00
Zack Scholl 52182099eb bump 8.1.1 2020-08-27 08:13:07 -07:00
Zack Scholl e250eeede6 add makefile for releases 2020-08-27 08:12:47 -07:00
Zack Scholl 4aa7f05630 slightly more debugging 2020-08-27 08:10:44 -07:00
Zack Scholl 3a805f8be3 bump 8.1.0 2020-08-26 19:16:25 -07:00
Zack Scholl 588e650d80 don't split host if localhost 2020-08-26 17:46:35 -07:00
Zack Scholl baddb93c4e local ipv6 works 2020-08-26 14:56:57 -07:00
Zack Scholl c9a58513e1 attempt to use ipv6 discoveries 2020-08-26 14:42:49 -07:00
Zack Scholl 8f13aedc19 thanks 2020-08-26 10:00:56 -07:00
Zack Scholl c0a05401c9 update deps 2020-08-26 09:58:06 -07:00
Zack Scholl ae384490d6 don't create folder if its a . 2020-08-26 09:55:59 -07:00
Zack e3ed4ba998
Merge pull request #228 from lpar/cleanup
Improve error reporting
2020-08-26 09:50:24 -07:00
Zack 43480dd997
Merge pull request #227 from lpar/master
Initial IPv6 fixes
2020-08-26 09:49:16 -07:00
mathew 6874d9eede Improve error reporting 2020-08-22 18:12:09 -05:00
mathew 1b646d5528 Improve error reporting 2020-08-22 18:05:00 -05:00
mathew 827b5d3a86 Initial IPv6 fixes 2020-08-22 14:51:32 -05:00
Zack Scholl 0beeebc351 bump 8.0.13 2020-08-12 09:59:07 -07:00
Zack Scholl f4047d5500 remove snap 2020-08-12 09:59:00 -07:00
Zack Scholl 4deced8827 bump 8.0.13 2020-08-12 09:58:13 -07:00
Zack Scholl c260147714 ignore darwin386 2020-08-12 09:58:11 -07:00
Zack Scholl 81e9f772a1 bump 8.0.13 2020-08-12 09:57:18 -07:00
Zack Scholl 8b11c5b661 ignore darwin386 2020-08-12 09:57:06 -07:00
Zack Scholl 009f36f16c bump 8.0.13 2020-08-12 09:49:29 -07:00
Zack Scholl 73dec72a74 update deps 2020-08-12 09:49:06 -07:00
Zack Scholl ee9188b082
signed commit 2020-07-17 12:54:10 -07:00
Zack Scholl fdf383b2d7 bump 8.0.12 2020-07-15 10:48:52 -07:00
Zack Scholl 7fd8fda107 default to port 9009 if port is lost during discovery
fixes #222
2020-07-15 10:47:56 -07:00
Zack Scholl 1255a79a57 update deps 2020-07-14 15:34:57 -07:00
Zack Scholl b4e1ed2697 update deps 2020-06-19 13:23:32 -07:00
Zack Scholl 0377223a67 fix tests: generate file in reproducible way #218 2020-05-18 07:20:51 -07:00
Zack dd9cd82732
Create FUNDING.yml 2020-05-13 14:08:02 -07:00
Zack 91468709aa
update readme with number of ports for relay 2020-05-12 12:04:08 -07:00
Zack Scholl 23c21bcafd bump 8.0.11 2020-05-12 11:33:03 -07:00
Zack Scholl 78b643792e revert 2020-05-12 11:30:00 -07:00
Zack Scholl 532cfa9cd9 bump 8.0.11 2020-05-12 05:41:57 -07:00
Zack Scholl cf6b13d156 add personal files to plugs #190 2020-05-12 12:39:15 +00:00
Zack 9440d8eb04
add gif 2020-05-08 11:00:07 -07:00
Zack Scholl 14f6a4a8be add example gif 2020-05-08 10:58:51 -07:00
Zack Scholl 93e45c6942 bump 8.0.10 2020-05-06 10:55:14 -07:00
Zack Scholl 6dc44ec002 faster pake 2020-05-06 10:50:57 -07:00
Zack Scholl 4211cea92e add benchmark for tcp connection 2020-05-06 10:18:39 -07:00
Zack Scholl 1740bda985 bump 8.0.9 2020-05-01 07:00:17 -07:00
Zack Scholl 189d1f7b2a update deps 2020-05-01 06:59:09 -07:00
Zack Scholl 86ebbaa618 bump 8.0.8 2020-04-24 08:17:24 -07:00
Zack Scholl 2e7708e3cd whoops 2020-04-22 07:08:08 -07:00
Zack Scholl cb522f2f06 debugging the comm 2020-04-22 06:24:47 -07:00
Zack Scholl 97f7f28f6e update deps 2020-04-20 12:33:16 -07:00
Zack Scholl 3ed036b51d bug fix: increase deadline for reading in channels, addresses #211 2020-04-20 12:30:07 -07:00
Zack Scholl a3e81e1d87 bump 8.0.7 2020-04-09 10:12:30 -07:00
Zack Scholl e56e65207f bump 8.0.7 2020-04-09 09:55:36 -07:00
Zack Scholl f6ea7243ea update readme 2020-04-09 09:54:58 -07:00
Zack Scholl f9f4f291da use debug instead of warn/error addresses #205 2020-04-09 09:54:04 -07:00
Zack d1c2777906
Merge pull request #209 from maximbaz/relay-show-version-on-startup
relay: show version on startup
2020-04-09 09:50:21 -07:00
Zack 0860283407
Merge pull request #210 from maximbaz/add-systemd-service
Add systemd service
2020-04-09 09:49:55 -07:00
Maxim Baz cb025ae8d4
Add systemd service
A while ago a user contributed this systemd service to Arch package, I thought it would make sense to have it available in the repo itself, so that (a) other people can find it easier and (b) if there are any improvements, the entire community will benefit of them.
2020-04-09 18:14:00 +02:00
Maxim Baz c058bcbb6b
relay: show version on startup
Since relay is a long-running process, I find myself in situations where I dont know which version of croc I have running.

This simple startup log will make it obvious.
2020-04-09 17:44:19 +02:00
Zack Scholl 9bf470ef29 bump 8.0.6 2020-04-09 08:02:10 -07:00
Zack Scholl 11d4fead2c update deps 2020-04-09 08:01:20 -07:00
Zack Scholl 9c0bc3efc3 bug fix: two read deadlines to prevent memory leak
addresses #205
2020-04-09 07:40:39 -07:00
Zack Scholl 386f4ff958 bump 8.0.5 2020-03-31 13:43:13 -07:00
Zack Scholl 97bf35bf93 fix debug 2020-03-31 13:42:52 -07:00
Zack Scholl f8fd239eec bump 8.0.5 2020-03-31 13:34:10 -07:00
Zack Scholl 72378947b5 update progressbar, show external ip on receiver 2020-03-31 13:33:27 -07:00
Zack Scholl b0125b63e7 test should not exceed max bytes 2020-03-27 09:38:09 -07:00
Zack Scholl b60a841044 bug fix: prevent crazy number of bytes getting into comm 2020-03-27 09:32:41 -07:00
Zack Scholl 44c3d43fa0 bump 8.0.4 2020-03-24 08:37:14 -07:00
Zack Scholl 7a605dd5c8 update deps 2020-03-24 08:36:52 -07:00
Zack Scholl aae56043cf bug fix: lock the chunk map
addresses #204
2020-03-18 03:06:50 +00:00
Zack Scholl 09d35d248f bump 8.0.3 2020-03-08 07:15:32 -07:00
Zack Scholl 03fe1c770a bump 8.0.2 2020-03-06 07:15:04 -08:00
Zack Scholl 1dd75c4bc3 better error messages 2020-03-06 07:12:08 -08:00
Zack Scholl 8b6500adfd hide most of the code phrase to use as authentication 2020-03-06 07:05:04 -08:00
Zack Scholl 3cf474e6e8 more tests 2020-03-02 10:10:17 -08:00
Zack Scholl 820225b684 more tests 2020-03-02 10:06:20 -08:00
Zack Scholl eddf361893 bump 8.0.1 2020-03-02 09:42:34 -08:00
Zack Scholl 2d6206b84f bump 8.0.1 2020-03-02 09:35:35 -08:00
Zack Scholl 074a869d6e bump 8.0.0 2020-03-02 09:04:25 -08:00
Zack 0c305fee08
Merge pull request #201 from schollz/v8
V8
2020-03-02 09:03:28 -08:00
Zack Scholl 5e37a308fe throw error when submitting bad passphrase to relay 2020-02-28 17:05:03 -08:00
Zack Scholl bc1f89ff68 bump 8.0.0 2020-02-28 16:57:46 -08:00
Zack Scholl 788a63cfa6 update deps 2020-02-28 13:31:04 -08:00
Zack Scholl a87b571376 update dockerifle 2020-02-28 13:30:39 -08:00
Zack Scholl 0b99be5b30 update year 2020-02-28 13:27:44 -08:00
Zack Scholl c3adc2981f encrypt external ip 2020-02-28 13:02:23 -08:00
Zack Scholl 5fce2a2e27 encrypt external ip 2020-02-28 12:58:46 -08:00
Zack Scholl d5846bc88d encrypt all communication with relay 2020-02-28 11:59:56 -08:00
Zack 2217f7ca61
Thanks! 2020-02-18 11:44:15 -08:00
Zack Scholl 4c56ec283d bump 6.4.11 2020-02-18 11:28:36 -08:00
Zack Scholl bc0841d8a1 update deps 2020-02-18 11:25:02 -08:00
Zack d4cbe03d0d
Merge pull request #198 from rkuprov/shared-secret-update
croc: secret phrase parsing
2020-02-18 10:51:29 -08:00
Roman df79b2ed8e croc: secret phrase parsing
what:
- `croc alpha beta gamma` is now properly understood as
 `croc alpha-beta-gamma`.

why:
- to increase convenience.
2020-02-17 21:31:56 -07:00
Zack Scholl 29882db39b bump 6.4.10 2020-01-15 09:14:37 -08:00
Zack Scholl 073569f292 need to add network bind to snap 2020-01-15 09:14:06 -08:00
Zack Scholl d6694a9b41 bump 6.4.9 2020-01-15 08:07:22 -08:00
Zack Scholl 5369fbc3aa bump 6.4.9 2020-01-15 08:06:28 -08:00
Zack Scholl 03d9785408 update deps, add snapcraft plugs 2020-01-15 08:06:08 -08:00
Zack Scholl fbcad738bb bump 6.4.8 2019-12-23 14:49:22 -08:00
Zack Scholl fd20b25a30 update deps 2019-12-23 14:48:44 -08:00
Zack Scholl aa54ff18e5 add snap install directions 2019-12-23 07:57:44 -08:00
Zack Scholl 44286ce473 thanks! 2019-12-23 07:56:44 -08:00
Zack Scholl 4824033619 clearly specify password 2019-12-23 07:55:10 -08:00
Zack 493ae9306d
Merge pull request #185 from xenrox/docker-pass-support
Support relay password for docker
2019-12-23 07:53:04 -08:00
Zack Scholl 25902edf5b bump 6.4.7 2019-12-16 07:38:56 -08:00
Zack Scholl 3d9bbff7a7 bump 6.4.7 2019-12-16 07:38:18 -08:00
Zack Scholl 02be7abe32 bump 6.4.7 2019-12-16 07:37:57 -08:00
Zack Scholl 4dd2922b5f fix snapcraft 2019-12-16 07:37:30 -08:00
Thorben Günther 06dd3ba62f
Don't force users to set $CROC_PASS 2019-12-07 02:06:01 +01:00
Thorben Günther 1ae85758f0
Support relay password for docker 2019-12-06 12:31:26 +01:00
Zack f12940bbcd
Merge pull request #183 from TheQueasle/fresh-mac-path-missing
Adding a function that creates the prefix
2019-11-26 12:50:33 -08:00
Micheal Quinn 247a698757 Adding in EUID check to create_prefix. Also adding in more checks to that function to make sure the tools needed are available. 2019-11-26 14:18:30 -06:00
Micheal Quinn 47d84b9947 Adding rcode for completness sake on the create_prefix function. 2019-11-26 13:50:31 -06:00
Micheal Quinn f6ad8f57cf Adding a function that creates a prefix and logic surrounding it to only create it if it does not already exist 2019-11-26 13:41:38 -06:00
Zack 24cb8f0103
Update README.md 2019-11-26 09:50:16 -08:00
Zack Scholl f52447acd9 bump 6.4.6 2019-11-21 15:24:25 -08:00
Zack Scholl 3c03719863 need to close goroutine corrrectly 2019-11-21 15:10:21 -08:00
Zack Scholl 5bafc99741 check if the purported IP is really local #168 2019-11-21 14:58:48 -08:00
Zack Scholl 20061b484e bump 6.4.5 2019-11-19 16:39:38 -08:00
Zack 88c4257816
Merge pull request #180 from maximbaz/support-default-port-receiver
Support default port on receiver side
2019-11-19 16:38:40 -08:00
Maxim Baz 1a544e4624
Support default port on receiver side 2019-11-20 01:11:52 +01:00
Zack Scholl eb85477086 bump 6.4.4 2019-11-19 15:25:33 -08:00
Zack Scholl 5faacd3328 try 9009 port by default #178 2019-11-19 15:19:53 -08:00
Zack 04cad7b9a5
thanks! 2019-11-19 14:05:05 -08:00
Zack Scholl 60d6489c69 bump 6.4.3 2019-11-19 14:01:57 -08:00
Zack 0e555179f8
Merge pull request #176 from maximbaz/patch-2
Add version to the dir name in the source tarball
2019-11-19 14:01:20 -08:00
Zack 3d672d6ac2
Merge pull request #179 from maximbaz/remember-relay-password-receive
Remember relay password on receive too #177
2019-11-19 14:00:34 -08:00
Maxim Baz b27b814b49
Switch to GlobalIsSet 2019-11-19 22:58:35 +01:00
Maxim Baz cc6af6e5e8
Checkout the version tag when cloning repo 2019-11-19 22:57:24 +01:00
Maxim Baz 252475f72e
Remember relay password on receive too #177 2019-11-19 21:06:12 +01:00
Zack Scholl e3ba938582 set relay password when remembering #177 2019-11-19 11:47:04 -08:00
Maxim Baz 1cdccfa884
Add version to the dir name in the source tarball 2019-11-19 19:38:29 +01:00
Zack Scholl e84e89b786 bump 6.4.2 2019-11-19 10:15:44 -08:00
Zack Scholl fb35da42ed upload separately 2019-11-19 10:15:02 -08:00
Zack Scholl d91ce7e469 bump 6.4.2 2019-11-19 10:12:18 -08:00
Zack Scholl cbc55a84a7 add snapcraft back 2019-11-19 10:12:07 -08:00
Zack Scholl 0694d61294 add upload asset to goreleaser #172 2019-11-19 09:24:13 -08:00
Zack f102195354
Merge pull request #175 from apeyrat/master
croc is now available in the main scoop bucket
2019-11-19 07:05:29 -08:00
Alain a5571306c2
croc is now available in the main bucket
No need to add dedicated channel as it is available in the main bucket.
See: https://github.com/ScoopInstaller/Main/blob/master/bucket/croc.json
2019-11-19 13:24:54 +01:00
Zack Scholl 60030cdfbb bump 6.4.1 2019-11-18 14:31:29 -08:00
Zack Scholl 181dee9991 quit on bad password 2019-11-18 14:26:01 -08:00
Zack Scholl bcb2b5d783 fix tests 2019-11-18 13:27:22 -08:00
Zack Scholl af95cddd8d fix tests 2019-11-18 13:25:51 -08:00
Zack Scholl 6b26af4dca bump 6.4.0 2019-11-18 13:15:51 -08:00
Zack Scholl b9b3995f02 exit on EOF 2019-11-18 13:15:41 -08:00
Zack Scholl d0c2dc1be8 use one-byte pings 2019-11-18 13:09:17 -08:00
Zack 544d3e0144 Update issue templates 2019-11-18 12:07:35 -08:00
Zack Scholl c369f67745 fix src bundle 2019-11-18 12:02:54 -08:00
Zack Scholl 76fc3f1a77 fix tests 2019-11-18 11:13:36 -08:00
Zack Scholl baf5d6f27f bump 6.3.0 2019-11-18 10:43:28 -08:00
Zack Scholl 497ffb8c2f update deps 2019-11-18 10:43:14 -08:00
Zack Scholl 7b5acc89a4 remove snapcraft for now 2019-11-18 10:42:42 -08:00
Zack Scholl eb22400db0 bump 6.3.0 2019-11-18 10:23:29 -08:00
Zack Scholl 79e5f4445b fix goreleaser 2019-11-18 10:23:27 -08:00
Zack Scholl 0f15698970 bump 6.3.0 2019-11-18 10:21:13 -08:00
Zack Scholl 419a766c6f fix goreleaser 2019-11-18 10:21:10 -08:00
Zack Scholl 19b5923f48 bump 6.3.0 2019-11-18 10:20:29 -08:00
Zack Scholl 2f2e19aa91 add snap to croc 2019-11-18 10:15:57 -08:00
Zack Scholl ae412375ef Merge branch 'master' of github.com:schollz/croc 2019-11-18 08:18:37 -08:00
Zack Scholl 21c1efe319 fix tests 2019-11-18 08:18:30 -08:00
Zack 4206605a2d
Merge pull request #174 from schollz/pass
implement password addresses #173
2019-11-18 08:17:03 -08:00
Zack Scholl 9d5eec4246 implement password addresses #173 2019-11-18 08:16:19 -08:00
Zack Scholl 3941762bf3 allow disabling multiplexing 2019-11-18 07:57:12 -08:00
Zack Scholl 648c41d707 use siec 2019-11-18 07:53:57 -08:00
Zack Scholl c7f419ca2d use functional encryption 2019-11-18 07:50:43 -08:00
Zack Scholl fe8dad42f7 bump 6.2.4 2019-11-18 07:42:09 -08:00
Zack Scholl 6a036d68f6 update releaser 2019-11-18 07:36:49 -08:00
rain1 b755d3f827 Update README.md
remove link to release
2019-11-18 07:36:49 -08:00
rain1 25776a1d96 Update README.md 2019-11-18 07:36:49 -08:00
rain1 9ec23ae367 Update README.md
remove curl | bash recommendation
2019-11-18 07:36:49 -08:00
Zack 43927a6dbb
Merge pull request #152 from HugoReeves/master
readme: add nix install instructions
2019-11-17 13:23:55 -08:00
Zack Scholl b8bcbb3ecc bump 6.2.3 2019-11-17 13:20:45 -08:00
Zack Scholl b7625ef55c add more info on how to send 2019-11-17 13:19:27 -08:00
Zack Scholl b7565177be fix tests 2019-11-17 13:05:43 -08:00
Zack Scholl a7aed67c65 bump 6.2.2 2019-11-17 13:00:41 -08:00
Zack Scholl b4f8fafb63 don't hang it no acceptance
Fixes #171
2019-11-17 12:59:29 -08:00
Zack Scholl 04724f4900 bump 6.2.1 2019-11-17 09:44:02 -08:00
Zack Scholl b2e81fb50d update deps 2019-11-17 09:41:50 -08:00
Zack 1754333ac0
Merge pull request #170 from maximbaz/patch-1
Add Arch Linux installation to README
2019-11-13 08:15:21 -08:00
Maxim Baz f3799213b6
Add Arch Linux installation to README 2019-11-13 01:41:41 +01:00
Zack bfa7768781
Update README.md 2019-11-12 12:14:42 -08:00
Zack Scholl acd7d8d8ec add profiling lines 2019-11-11 11:26:32 -08:00
Zack Scholl bdb8bf3ac4 addresing CPU usage #168 2019-11-11 11:26:12 -08:00
Zack a0d9d74d5d
Merge pull request #166 from taigrr/master
Update README.md
2019-11-03 17:18:39 -07:00
Tai Groot 68f039fbb0
Update README.md
Removed v6 that causes error from build from source instructions
2019-11-03 16:09:07 -08:00
Zack 9afae3b6b0
Merge pull request #164 from schollz/prepend
Prepend payload with 'croc' so no interference from other broadcasts
2019-10-28 13:15:47 -07:00
Zack Scholl c7624535e9 skip discovery 2019-10-28 13:13:03 -07:00
Zack Scholl da626334e0 check discoveries for right prefix 2019-10-28 12:46:24 -07:00
Zack Scholl aaeda77af4 bump 6.2.0 2019-10-24 07:22:57 -07:00
Zack Scholl ffddd3e989 prompt if sender wants to ask 2019-10-24 06:58:12 -07:00
Zack 4b8d32ff75
Merge pull request #161 from schollz/ask
ask using the machine ID for extra secure layer Fixes #159
2019-10-23 15:01:55 -07:00
Zack Scholl 9aa327a0a4 use machine ID 2019-10-23 14:59:47 -07:00
Zack Scholl 42c2d5c6c1 add ask flag 2019-10-23 14:07:52 -07:00
Zack 41b91a3baf
Merge pull request #157 from TheQueasle/centos8_support
Adding in a more detailed error message for when an extraction tool is not found.
2019-10-09 09:45:08 -07:00
Micheal Quinn 183791d4c4
Adding in a more detailed error message for when an extraction tool is not found in PATH. CentOS 8 Minimal install seems to not include tar... 2019-10-08 22:49:32 -05:00
Zack c4d8c168a3
Update .travis.yml 2019-10-08 16:35:11 -07:00
Zack Scholl e286321d39 bump 6.1.5 2019-10-07 16:22:58 -07:00
Zack Scholl af39b8ca14 pad filenames according to longest filename 2019-10-07 16:20:24 -07:00
Zack 810a04509a
Update .travis.yml 2019-10-03 13:00:00 -07:00
Zack Scholl 59666c564d bump 6.1.4 2019-10-03 12:09:18 -07:00
Zack Scholl 00e6ac9316 bump 6.1.4 2019-10-03 12:08:18 -07:00
Zack Scholl 7a1fb8db24 update deps 2019-10-03 12:07:45 -07:00
Zack Scholl 5d89bdb6f9 reduce complexity 2019-09-20 10:06:50 -07:00
Zack Scholl c46a9d3ae0 reduce complexity 2019-09-20 10:06:26 -07:00
Zack Scholl ae81dd9a7b reduce complexity 2019-09-20 10:05:29 -07:00
Zack Scholl 4e94a22300 reduce complexity 2019-09-20 10:03:06 -07:00
Zack Scholl 8be63bed43 reduce complexity 2019-09-20 10:00:52 -07:00
Zack Scholl a7435a08bd reduce complexity 2019-09-20 09:59:24 -07:00
Zack Scholl 22ead388cd reduce complexity 2019-09-20 09:57:18 -07:00
Zack Scholl 7ac7e5d56d reduce complexity 2019-09-20 09:54:10 -07:00
Zack Scholl cfbd65be31 reduce complexity 2019-09-20 09:47:47 -07:00
Zack Scholl 07c20e2cde reduce complexity 2019-09-20 09:45:42 -07:00
Zack Scholl 24abf4fdd8 reduce complexity 2019-09-20 09:43:16 -07:00
Zack Scholl 768ad9b739 reduce complexity 2019-09-20 09:41:58 -07:00
Zack Scholl 6202d0d932 reduce complexity 2019-09-20 09:32:32 -07:00
Zack Scholl 049a4aaffc reduce complexity 2019-09-20 09:27:59 -07:00
Zack Scholl 1fe8ccf3ab reduce complexity 2019-09-20 09:24:10 -07:00
Zack Scholl 9fb54a3952 reduce complexity 2019-09-20 09:20:50 -07:00
Zack a0e2876741
Merge pull request #153 from TheQueasle/install_script_rewrite
Install script rewrite
2019-09-10 07:41:07 -07:00
Micheal Quinn 932f037b17
Moving the new script back into place. I think the merge conflict is resolved now. 2019-09-10 07:31:13 -05:00
Micheal Quinn fe4e9c357a
Upping version of croc in the installer script. 2019-09-10 07:30:31 -05:00
Micheal Quinn c0f7c3c250
Merge branch 'master' of https://github.com/schollz/croc into install_script_rewrite 2019-09-10 07:29:24 -05:00
Micheal Quinn f01165e9f4
Trying to get out of this merge confilct 2019-09-10 07:29:17 -05:00
Micheal Quinn 5fbb787a84
Adding in message and exit for cygwin. 2019-09-10 07:20:39 -05:00
Zack Scholl 24801dfc24 coverage improved 2019-09-08 06:14:33 -07:00
Zack Scholl 5ad631e7b6 add more tests 2019-09-08 06:12:16 -07:00
Zack Scholl cc728a1138 fix minor bug 2019-09-08 06:07:53 -07:00
Zack Scholl b979607c42 fix 2019-09-08 05:56:57 -07:00
Zack Scholl f89dd01e87 add more tests 2019-09-08 05:53:30 -07:00
Zack Scholl 6287a7b7f7 add coveralls link 2019-09-07 10:40:30 -07:00
Zack Scholl 22f6a13a9f add more tests 2019-09-07 10:31:18 -07:00
Zack Scholl a82dd2f284 improve tests 2019-09-07 10:06:41 -07:00
Zack Scholl 33aa006c26 fix spelling 2019-09-07 09:49:08 -07:00
Zack Scholl 845dabbae0 Merge branch 'master' of github.com:schollz/croc 2019-09-07 09:46:08 -07:00
Zack Scholl 31c1a37b38 fix linting 2019-09-07 09:46:04 -07:00
Zack Scholl 0277abe5d4 gofmt -s -w 2019-09-07 09:41:24 -07:00
Zack 175b9a3f76
Update README.md 2019-09-07 08:18:21 -07:00
Zack Scholl 9a70ea90d1 bump 6.1.3 2019-09-07 07:41:03 -07:00
Zack bc6803eeef
use single reader (#155)
* dunno

* close file after finished

* fix debugging statements

* use single reader

* update deps
2019-09-07 07:34:05 -07:00
Zack Scholl fb658ccde2 update deps 2019-09-04 09:00:29 -07:00
Zack Scholl de7a29470b bump 6.1.2 2019-08-27 17:11:58 -07:00
Zack Scholl 4150feddf0 skip checking each file each time 2019-08-27 09:51:37 -07:00
Micheal Quinn 97f65bf51d
Adding in stdout of checksum check if the check fails 2019-08-23 11:50:40 -05:00
Micheal Quinn 07a2abd808
Adding in a banner...because all the cool kids are doing it. 2019-08-23 11:05:57 -05:00
Zack Scholl 7515c92a8b update deps 2019-08-22 13:22:31 -07:00
Micheal Quinn 7a6c4db5f9
Moving new file to default.txt. Removed todo (will be recreated in the pull request to come) 2019-08-21 22:47:51 -05:00
Micheal Quinn e3e7ada3e6
Updating todo 2019-08-15 20:50:33 -05:00
Micheal Quinn 105357bcbf
Updating todo 2019-08-15 20:49:30 -05:00
Micheal Quinn d6d96e487f
fixing returncode for download_file 2019-08-15 20:48:46 -05:00
Micheal Quinn d3207e6190
First pass of upping rcodes for some of the functions that may have tool return codes clash. Also changing some logic for determine_os and determine_arch to make it a little more better 2019-08-15 20:06:04 -05:00
Quinn 51e77ba0c4
Update rewrite_todo.md 2019-08-14 17:07:43 -05:00
Quinn f3efbb34af
Update rewrite_todo.md 2019-08-14 17:04:21 -05:00
Quinn 9e9f43c352
Update rewrite_todo.md 2019-08-13 23:16:46 -05:00
Quinn 27bc2e8c8a
Update rewrite_todo.md 2019-08-13 23:09:13 -05:00
Quinn 559807f97d
Forgot to update the function name for cygwin 2019-08-13 22:51:06 -05:00
Quinn a31bc56c23
More Cygwin updates
Forgot to update the install logic case statement in main
2019-08-13 22:45:59 -05:00
Quinn a9caea4d64
More WIndwos (cygwin) updates
Add install_file_cygwin function to support this case
2019-08-13 22:41:48 -05:00
Quinn ec09a990af
Adding croc_dl_ext update
For when we are on a Windows/CYGWIN host
2019-08-13 22:34:40 -05:00
Micheal Quinn a72172d11e
Adding update to checksum check function to always filter the checksum file based on downloaded file. Adding CYGWIN croc_os switch for windows support (needs more testing) 2019-08-13 22:28:26 -05:00
Hugo Reeves 53328fa58b
readme: add nix install instructions 2019-08-14 11:09:13 +12:00
Quinn 081e267a19
check off bsds 2019-08-12 21:15:38 -05:00
Quinn d429e09e95
quick todo file 2019-08-12 21:15:06 -05:00
Micheal Quinn 588dfe6c00
Removing cleanup logic. rm -rf in a script terrifies me. The script attempts to place it into the temp dir, so we will let the OS clean it up. 2019-08-12 14:40:46 -05:00
Micheal Quinn e2e48d9e84
Adding in fix for macOS (Darwin) not having an install case. Uses the same logic from install_file_freebsd 2019-08-12 11:04:50 -05:00
Micheal Quinn b8d1d11b68
Changing PREFIX to INSTALL_PREFIX to avoid clashing with possibly set environment variables. Adding logic to handle if we are on termux on android (adapted from previous croc install script). Adding an info message for what prefix was set to. Adding in armv71 support (need to add more or make this a generic case to catch more arm devices). 2019-08-12 10:53:09 -05:00
Micheal Quinn 34743118de
script header cleanup 2019-08-12 09:16:24 -05:00
Micheal Quinn 9c6f01ca91
swapping getopt (which apparently is not good to use) for getopts in an attempt to make it more cross-platform without having to break out the logic based on OS...again... 2019-08-11 17:07:43 -05:00
Micheal Quinn d39266a36d
wrangling another batch of wild global vars that should be local vars 2019-08-11 16:35:51 -05:00
Micheal Quinn bf15c4c424
Adding help message formatting. Adding in sudo check. Caught and fixed some global variables that should be local. 2019-08-11 16:00:56 -05:00
Micheal Quinn 2c2920eb9c
Adding description information. Added print message function for fancy colors in the output. 2019-08-11 15:33:42 -05:00
Micheal Quinn e7d6d096a8
Adding in root check to install commands with fallback to sudo. Splitting install logic out based on host OS 2019-08-11 13:01:00 -05:00
Micheal Quinn b0ac5024a4
Adding a function to handle creation of temp dir. Polished the checksum check function to handle more cases/OSes 2019-08-11 12:31:19 -05:00
Micheal Quinn 9530952eb6
Adding install function and cleanup function 2019-08-10 21:45:53 -05:00
Micheal Quinn eaf448ddac
Adding install function and logic 2019-08-10 21:08:04 -05:00
Micheal Quinn c82dda45d9
Adding in extract file logic. 2019-08-10 18:26:06 -05:00
Micheal Quinn 7a684e7266
moving the rewrite into the proper location 2019-08-10 17:57:37 -05:00
Micheal Quinn 6178a7e16b
First pass at a rewrite. 2019-08-10 17:56:54 -05:00
Zack 02f89b1854
Merge pull request #150 from TheQueasle/freebsd_support_and_checksum_fixes
Install Script FreeBSD Support and Checksum Checks Fixes
2019-08-02 13:27:13 -07:00
Micheal Quinn d5a8d07d1c
Fixing the macos shasum call to fit into the checksum check 2019-08-02 14:37:56 -05:00
Micheal Quinn 2c27d7aabd
reverting line 147 2019-08-01 13:02:44 -05:00
Micheal Quinn f8d60c0011
Adding in some fixes for FreeBSD (tested in a FreeNAS jail 'FreeBSD 11.2-STABLE') as well as a fix for the checksum logic not correctly comparing the checksums. This still needs testing on a MacOS host 2019-08-01 12:55:05 -05:00
Zack Scholl e1e722fc5b bump 6.1.1 2019-07-20 10:01:10 -06:00
Zack Scholl 82f2c8cd2f require go1.12 2019-07-20 08:57:03 -07:00
Zack Scholl 88b4001dd7 bug fix: create directories for empty files 2019-07-20 08:55:54 -07:00
Zack Scholl 2735c42a9d send empty files 2019-07-19 17:46:02 -07:00
Zack Scholl 83db5bdc68 Merge branch 'master' of https://github.com/schollz/croc 2019-07-19 17:42:22 -07:00
Zack Scholl fe1329c909 handle if the file is zero bytes 2019-07-19 17:39:25 -07:00
Zack Scholl 336f314854 bump 6.1.0 2019-07-18 07:22:38 -06:00
Zack Scholl 6f31418330 add --remember 2019-07-18 07:22:03 -06:00
Zack bd7ab1a9be
Merge pull request #144 from schollz/config
add --remember for saving config parameters
2019-07-18 06:18:38 -07:00
Zack Scholl edc97915bd don't keep debug 2019-07-18 06:17:15 -07:00
Zack Scholl 256e0c51fa add save file for receiver 2019-07-18 06:13:11 -07:00
Zack Scholl 7fcf45cece remove unused code 2019-07-18 06:06:56 -07:00
Zack Scholl 6a8bdccb66 add receiver config 2019-07-17 18:16:50 -06:00
Zack Scholl 252e96a670 simplify toggling 2019-07-17 18:06:52 -06:00
Zack Scholl 97d18e1fbf toggling parameters 2019-07-17 17:26:42 -06:00
Zack Scholl 54fb8aec9d how to check if flag is set? 2019-07-17 17:23:50 -06:00
Zack Scholl 1d7976a61a save send remember 2019-07-17 16:19:32 -06:00
Zack Scholl f18c2eae7e add get config dir 2019-07-17 15:55:43 -06:00
Zack Scholl 68ddbe7f14 small change 2019-07-17 14:33:02 -06:00
Zack Scholl 8b178881cf display relay in UI if not using default
Fixes #143
2019-07-17 14:12:48 -06:00
Zack Scholl 9968bbf824 addressing issue #141
the local relay is not being used and then the connection is refused but it still hangs
in that case is that the sender should give up, prompting the user to try again
2019-07-17 13:04:03 -06:00
Zack Scholl 928ee1f496 bump 6.0.12 2019-07-14 20:33:47 -06:00
Zack Scholl fbbdd1bcfe update deps 2019-07-14 20:32:42 -06:00
Zack Scholl f6cafd76fd Merge branch 'master' of github.com:schollz/croc 2019-07-14 19:31:53 -07:00
Zack Scholl fe231fa67a remove machineid from deps 2019-07-14 19:31:44 -07:00
Zack Scholl 6091e9348e update deps 2019-07-08 14:21:29 -06:00
Zack Scholl 57564314b0 bump 6.0.11 2019-07-06 10:17:37 -06:00
Zack 6d9105abfb
Docker (#134)
* docker file works

* add docker info
2019-07-04 18:20:25 -07:00
Zack Scholl ba00eda176 bump 6.0.10 2019-06-20 07:10:37 -07:00
Zack Scholl 1d744f1b4a bump version 2019-06-17 13:28:56 -06:00
Zack Scholl 0519850bc3 update deps 2019-06-17 13:28:29 -06:00
Matthew Helmke e5d59fe563 Small fix (#132)
Just fixing a simple typo.
2019-06-17 07:46:52 -07:00
Zack Scholl f35c5b88b6 bump 2019-06-11 10:05:34 -06:00
Zack Scholl 2e2700988b update deps 2019-06-04 09:31:24 -06:00
Zack Scholl 15034cc6d2 bump version 2019-05-27 08:01:37 -07:00
Zack Scholl b1022a3408 update deps 2019-05-27 07:58:23 -07:00
Zack Scholl 1975745d5f remove after test 2019-05-12 13:10:17 -06:00
Zack Scholl 6b288356b9 remove big file after testing 2019-05-12 13:09:10 -06:00
Zack bcb348a776
Update .travis.yml 2019-05-12 10:22:53 -07:00
Zack Scholl 59b6558ce9 bump 2019-05-12 09:31:22 -06:00
Zack 29915596ed
do cleanup 2019-05-12 08:24:06 -07:00
Zack Scholl 8bdc71a06c version bump 2019-05-12 08:55:42 -06:00
meyermarcel cba650193d Add publishing to scoop bucket (#130) 2019-05-12 07:54:03 -07:00
Zack acae0abb24
Thanks @meyermarcel 2019-05-10 11:59:39 -07:00
meyermarcel a23347a823 Replace deprecated 'archive' key with new 'archives' key (#129) 2019-05-10 11:58:53 -07:00
Zack Scholl c45d3c01e5 bump version 2019-05-10 07:16:00 -06:00
Zack 59736eefd8
Update goreleaser.yml 2019-05-10 06:12:55 -07:00
meyermarcel f5e1bab6b5 Add publishing to homebrew repository (#128) 2019-05-10 06:11:14 -07:00
Zack Scholl ae6ce06836 release not draft 2019-05-09 23:05:20 -06:00
Zack Scholl 30f1233f74 fix tests 2019-05-09 23:02:35 -06:00
Zack Scholl f91d52bead update version 2019-05-09 22:59:33 -06:00
Zack Scholl b71e1e78ca update deps 2019-05-09 22:58:28 -06:00
Zack Scholl 0388e07689 remove flushing 2019-05-08 21:33:30 +00:00
Zack Scholl da54ae060a update deps 2019-05-08 21:13:40 +00:00
Zack Scholl 257607a26f use my logger instead of seelog 2019-05-08 21:03:54 +00:00
Zack Scholl 8d3b240563 check room nil before closing 2019-05-06 14:56:17 -07:00
Zack Scholl ba96be5024 update hash 2019-05-03 21:19:39 -06:00
Zack Scholl bd9c7b5ae9 include hash 2019-05-03 21:19:04 -06:00
Zack Scholl cb69e49283 include hash in version 2019-05-03 20:15:29 -07:00
Zack Scholl a6512975ff fix debug statement 2019-05-03 13:55:17 -07:00
Zack 1f3d30c78e
Use relay as backup to find local ports (#127) 2019-05-03 13:51:27 -07:00
Zack Scholl fef1c3ca3b use imohash 2019-05-03 07:35:27 -07:00
Zack Scholl 9f9b93cf47 share chunk ranges instead of chunks Fixes #125 2019-05-03 07:30:35 -07:00
Zack Scholl 7d91f8200c better cleaning of empty rooms 2019-05-02 20:57:55 -07:00
Zack Scholl 1802ebcd00 use imohash 2019-05-02 20:53:02 -07:00
Zack Scholl ee38e7243e more debug 2019-05-02 20:51:13 -07:00
Zack Scholl da09151db2 more debug 2019-05-02 20:48:21 -07:00
Zack Scholl 63f4553e4b more debug 2019-05-02 20:47:41 -07:00
Zack Scholl 8beaf65007 more debug 2019-05-02 20:45:21 -07:00
Zack Scholl 5e8ef27b85 more debug 2019-05-02 20:44:25 -07:00
Zack Scholl 09575a0c88 more debug 2019-05-02 20:43:39 -07:00
Zack Scholl aeb30ef187 use xxhash 2019-05-02 20:36:49 -07:00
Zack Scholl 711690a0f2 use imohash as default as its faster 2019-05-02 20:28:31 -07:00
Zack Scholl ea115908fc fix readme go get 2019-05-02 18:33:52 -07:00
Zack Scholl 3e6a554532 get local IP 2019-05-02 17:14:24 -07:00
Zack Scholl 38e7cae977 document purged error 2019-05-02 17:12:19 -07:00
Zack Scholl 6f5225ac91 purge errors on successful transfer 2019-05-02 17:11:01 -07:00
Zack Scholl 19efe8b77a fix readme 2019-05-02 17:06:11 -07:00
Zack Scholl b7c817a04a update default.txt 2019-05-02 16:45:37 -07:00
Zack Scholl dccaff32cf default stdout 2019-05-02 16:37:43 -07:00
Zack f2e420cd2c
Merge pull request #124 from schollz/v61
version 6.0.0
2019-05-02 16:32:35 -07:00
Zack 02b0cbed06
Merge branch 'master' into v61 2019-05-02 16:32:15 -07:00
Zack Scholl e29179dd9c update readme 2019-05-02 16:06:57 -07:00
Zack Scholl 2da7fa22ad minor 2019-05-02 13:40:14 -07:00
Zack Scholl 2515cfa31e update version 2019-05-02 13:31:48 -07:00
Zack Scholl 78e4ee2b68 update version 2019-05-02 13:28:28 -07:00
Zack Scholl 2f4e5cdec4 update versoin 2019-05-02 13:25:03 -07:00
Zack Scholl 37b29aebce update version 2019-05-02 13:23:23 -07:00
Zack Scholl 9e61f38707 add go generate code for updating version 2019-05-02 13:14:09 -07:00
Zack Scholl 7377f536fc update ui and readme 2019-05-02 12:08:23 -07:00
Zack Scholl 462fad8d8e modify discover parameters 2019-05-02 11:50:01 -07:00
Zack Scholl 9cf4050913 no limit to sender discoveries 2019-05-02 11:47:19 -07:00
Zack Scholl aae63876d6 use local port 2019-05-02 11:45:42 -07:00
Zack Scholl 7af57b3390 slightly larger bar 2019-05-02 11:44:54 -07:00
Zack Scholl 2e5f33c081 print out securing 2019-05-02 11:44:10 -07:00
Zack Scholl 95c2b0f48a Don't throw error if cannot connect to server 2019-05-02 11:41:03 -07:00
Zack Scholl abc5e3f6c0 move install script 2019-05-02 11:31:26 -07:00
Zack Scholl 2b42c5365c don't show ui each time 2019-05-01 17:52:37 -06:00
Zack Scholl 67f69c892d use external ip in ui 2019-05-01 17:49:49 -06:00
Zack Scholl 359dc4549b share public ip as info 2019-05-01 17:44:09 -06:00
Zack Scholl b109b419de save the extenral ip 2019-05-01 17:27:49 -06:00
Zack Scholl 7162e5e45b collect ipaddr from connecting to tcp 2019-05-01 17:10:02 -06:00
Zack Scholl 494b224db0 fix 2019-05-01 13:49:58 -06:00
Zack Scholl 868051bc2a update ports 2019-05-01 13:48:09 -06:00
Zack Scholl 77b11e3c3f simplify readme 2019-05-01 13:20:30 -06:00
Zack Scholl ecfdb2d440 stdout should erase file 2019-05-01 13:09:47 -06:00
Zack Scholl eceddb364e reduce number of default ports 2019-05-01 12:32:00 -06:00
Zack Scholl 4a27806ffe allow local 2019-05-01 12:30:58 -06:00
Zack Scholl b55af54b10 change message 2019-05-01 12:20:02 -06:00
Zack Scholl e1745757ac change message 2019-05-01 12:17:53 -06:00
Zack Scholl be1c1d6206 change message 2019-05-01 12:16:47 -06:00
Zack Scholl 655ffdb4c0 delete room on errors 2019-05-01 12:11:20 -06:00
Zack Scholl 9f6936e1ff small fix 2019-05-01 12:08:24 -06:00
Zack Scholl 48819a9e03 disable local 2019-05-01 11:59:12 -06:00
Zack Scholl 6ac4343213 increase verbosity 2019-05-01 11:45:13 -06:00
Zack Scholl 29dceee8f4 fixes 2019-05-01 11:39:14 -06:00
Zack Scholl 5bffeabbba print connecting message 2019-05-01 11:03:16 -06:00
Zack Scholl f3e2a260d9 update relay address if a peer is found 2019-05-01 10:38:31 -06:00
Zack Scholl 883dff96b8 sender should be able to connect to the port 2019-05-01 10:33:34 -06:00
Zack Scholl 4be02ad249 get ports from tcp server 2019-04-30 17:39:36 -06:00
Zack Scholl 2c2c3f58ac ifix cliwq! 2019-04-30 23:26:32 +00:00
Zack Scholl ec8768bc70 activate travis 2019-04-30 17:20:11 -06:00
Zack Scholl 1275c6b1b5 get tcp port information from banner 2019-04-30 17:19:10 -06:00
Zack Scholl c5bbdb4cb5 allow banner 2019-04-30 17:09:44 -06:00
Zack Scholl 63ec16f7fb add banner 2019-04-30 17:05:19 -06:00
Zack Scholl 23c9a9cff8 longer bar 2019-04-30 16:26:16 -06:00
Zack Scholl 9952da9f6d use random salt 2019-04-30 16:10:07 -06:00
Zack Scholl e72795985b fix tests with nodisable flag 2019-04-30 15:46:27 -06:00
Zack Scholl a1e5a283f9 move file info stuff 2019-04-30 15:39:59 -06:00
Zack Scholl e8f465060f move todo to wiki 2019-04-30 15:32:52 -06:00
Zack Scholl 002cc0050c can switch between local and nonlocal 2019-04-30 13:07:30 -06:00
Zack Scholl a58a0df910 add peer 2019-04-30 12:55:18 -06:00
Zack Scholl 89e4871af2 redo 2019-04-30 12:49:51 -06:00
Zack Scholl f4d24a1f72 update 2019-04-30 12:46:35 -06:00
Zack Scholl 7060eec8d1 need two ways to connect 2019-04-30 11:39:45 -06:00
Zack Scholl a70aa0a4fc make initial connection 2019-04-30 11:35:27 -06:00
Zack Scholl 8f816304f9 make initial connection 2019-04-30 11:35:02 -06:00
Zack Scholl ce45c53b38 make initial connection 2019-04-30 11:32:11 -06:00
Zack Scholl a35779f718 block connection 2019-04-30 11:30:36 -06:00
Zack Scholl d1780e70b7 disable travis 2019-04-30 11:26:37 -06:00
Zack Scholl 3e9283dc01 add todo 2019-04-30 11:25:04 -06:00
Zack Scholl 2583313602 allow discovery 2019-04-30 11:23:53 -06:00
Zack Scholl b9d2be5378 add discovery 2019-04-30 11:19:03 -06:00
Zack Scholl 962ea50aee add back travis 2019-04-30 11:14:21 -06:00
Zack Scholl d56a25cf76 make sure bar finishes 2019-04-30 10:43:52 -06:00
Zack Scholl 346b2d9881 update deps 2019-04-30 10:28:34 -06:00
Zack Scholl c8fdd4726a simplify ui 2019-04-30 09:24:32 -07:00
Zack Scholl 3bf7635f33 improve ui 2019-04-30 08:58:09 -07:00
Zack Scholl 87d295f62b simplify bar add 2019-04-30 07:51:48 -07:00
Zack Scholl be7c2ad1fb check if missing chunks file exists 2019-04-30 07:47:05 -07:00
Zack Scholl 04844cf72c check if missing chunks file exists 2019-04-30 07:44:16 -07:00
Zack Scholl 6da93ae8da allow resume 2019-04-30 07:29:02 -07:00
Zack Scholl 4f20f3ce43 connect in parallel 2019-04-30 07:07:23 -07:00
Zack Scholl e54045ef5a read until 4 bytes 2019-04-30 07:07:07 -07:00
Zack Scholl 3c051f4283 smaller packet 2019-04-30 06:58:57 -07:00
Zack Scholl 000dfc15be fiX comm 2019-04-30 06:57:45 -07:00
Zack Scholl 330e76e09c fix 2019-04-29 21:33:13 -07:00
Zack Scholl 42d35898b5 progressbar is not accurate in total 2019-04-29 21:25:30 -07:00
Zack Scholl c1c8e39499 working 2019-04-29 20:40:42 -07:00
Zack Scholl 859130a988 add croc test 2019-04-29 19:51:54 -07:00
Zack Scholl 7d1f7adddb remove travis for now 2019-04-29 19:51:44 -07:00
Zack Scholl ac113dfe47 initial part works 2019-04-29 19:50:01 -07:00
Zack Scholl 972dce1ec5 don't hardcode address 2019-04-29 19:20:03 -07:00
Zack Scholl 662bce58a3 allow sending 2019-04-29 19:19:48 -07:00
Zack Scholl 9223fc79e9 allow option to skip encryption 2019-04-29 19:19:25 -07:00
Zack Scholl a17f3096a0 no isclosed 2019-04-29 18:55:37 -07:00
Zack Scholl 6b149480d4 add messaging 2019-04-29 18:03:19 -06:00
Zack Scholl a7f12ca179 need to export encryption 2019-04-29 17:58:37 -06:00
Zack Scholl 7d9b199ca3 works 2019-04-29 17:38:49 -06:00
Zack Scholl 06541ee0d3 encapsulate 2019-04-29 17:29:36 -06:00
Zack Scholl bbd7caa148 remove relay 2019-04-29 17:25:20 -06:00
Zack Scholl ca0b898ca3 add tests 2019-04-29 17:24:37 -06:00
Zack Scholl 3685a887b8 add bytecountdecimal 2019-04-29 17:16:38 -06:00
Zack Scholl 005a206460 update go.mod 2019-04-29 17:12:26 -06:00
Zack Scholl c1d66d5301 add go.sum 2019-04-29 17:12:12 -06:00
Zack Scholl cee4c36f8b prune 2019-04-29 17:12:04 -06:00
Zack Scholl 1661bbb221 remove wina nd zipper 2019-04-29 17:10:06 -06:00
Zack Scholl 7a8801f8f1 add the v5 main 2019-04-29 17:09:37 -06:00
Zack Scholl b52001e064 prune 2019-04-29 17:05:48 -06:00
Zack Scholl 1045bd17b5 update croc 2019-04-29 16:54:31 -06:00
Zack Scholl 1f49966bb1 use new version of croc 2019-04-29 16:48:17 -06:00
Zack Scholl dcc7689816 consolidate utils 2019-04-29 16:35:07 -06:00
Zack Scholl 376591384a add more to tests 2019-04-29 16:33:15 -06:00
Zack Scholl 9030aae880 fix test 2019-04-29 16:24:22 -06:00
Zack Scholl 2414593c91 test sending 40mb 2019-04-29 16:04:47 -06:00
Zack Scholl 5b0c52a97b don't dangle 2019-04-29 15:46:40 -06:00
Zack Scholl ef25c556a9 use pointers 2019-04-29 14:06:18 -06:00
Zack Scholl b9a5f450c5 simplify 2019-04-29 13:53:12 -06:00
Zack Scholl 8dc8783bd4 propogate errors 2019-04-27 17:03:05 -07:00
Zack Scholl f238c4b22c modify api of salt 2019-04-27 16:49:00 -07:00
Zack Scholl 249c0d8ab0 faster encryption by generating key once 2019-04-27 11:15:38 -07:00
Zack Scholl 14dd892377 tcp communication better/simpler 2019-04-27 09:20:03 -07:00
Zack 951b2a2548
Update README.md 2019-04-08 10:41:24 -07:00
Zack Scholl 7c731a90dc update travis go 2019-03-12 12:35:43 -06:00
Zack Scholl 003a2344e4 update deps 2019-03-12 12:32:46 -06:00
Zack 566694f381
bump version 2019-02-18 20:30:47 -08:00
Zack Scholl 9643fe748b update deps 2019-02-16 10:44:19 -08:00
Zack caaaff4bd5
Merge pull request #120 from wxitcode/patch-1
Update README.md
2019-02-01 22:25:10 -08:00
wxitcode e272af8794
Update README.md
Fix display issues
2019-02-02 12:14:27 +08:00
Zack bcce2c021d
update with correct relay information #117 2019-01-05 18:35:33 -08:00
Zack 148b10d666
Update default.txt 2019-01-01 16:10:39 -08:00
Zack Scholl af6cc64786 update deps 2019-01-01 17:01:17 -07:00
Zack Scholl fd8a1ebe7b activate go111modules in travis ci 2018-12-14 08:15:47 -07:00
Zack Scholl 6fa1b4c080 update gomod 2018-12-14 06:44:20 -08:00
Zack Scholl 7839d7f6e2 exclude gui from testing 2018-12-14 06:39:51 -08:00
Zack Scholl 43dbf98705 rotate multicast based on current time 2018-12-14 06:32:44 -08:00
Zack Scholl e58fc14218 customize multicast address 2018-12-14 06:27:55 -08:00
Zack d3fdb4257d
Merge pull request #115 from gonutz/master
Add pure Go Windows GUI
2018-11-20 21:06:17 -08:00
Lars d42a4f82a1 Add pure Go Windows GUI 2018-11-21 00:08:30 +01:00
Zack Scholl eaa3624977 bump version 2018-11-05 20:02:31 -07:00
Zack Scholl 068fdb77fc pass errors all the way back 2018-11-02 06:15:37 -07:00
Zack Scholl 8a882cc174 throttle the progress bar 2018-11-01 19:06:50 -07:00
Zack Scholl be70c8a83d bump version 4.1.3 2018-11-01 09:57:18 -07:00
Zack Scholl cf2363fd4e add missing escape at end of cli app 2018-11-01 09:08:18 -07:00
Zack Scholl 92648e0112 bump version 2018-11-01 08:45:59 -06:00
Zack Scholl 5ad34e1034 update deps 2018-11-01 08:45:22 -06:00
Zack 09f89a4958
Update go.mod 2018-11-01 07:29:23 -07:00
Zack 73aeaec822
Update go.mod 2018-11-01 07:29:11 -07:00
Zack Scholl e0081ea8a8 tell user codephrase is wrong if PAKE fails 2018-11-01 07:26:18 -07:00
Zack Scholl a56334fc60 prompt user if accidently receiving 2018-11-01 07:08:57 -07:00
Zack Scholl aefb15105a recipient quits if trying to connect without sender
Addresses #109
2018-11-01 06:56:40 -07:00
Zack Scholl 2b8f581ca4 check checksum for macos #111 2018-10-30 14:41:52 -07:00
Zack 737049694b
Fixes #110 2018-10-29 05:43:17 -07:00
Zack Scholl 818e590d92 need to do chdir in goroutine 2018-10-24 07:19:03 -07:00
Zack Scholl 034074d7a3 version 4.1.1 2018-10-24 07:52:13 -06:00
Zack Scholl e57f3e3861 need to watch slashes 2018-10-24 06:48:05 -07:00
Zack Scholl 0ca74b010e minor zip fixes
Allows multiple zips.

Need to close file after zipping it.
2018-10-24 06:42:27 -07:00
Zack Scholl fea07cab6c Merge branch 'master' of github.com:schollz/croc 2018-10-23 06:19:56 -07:00
Zack Scholl 562925b5e5 add missing execute bit for config dir 2018-10-23 06:19:53 -07:00
Zack c33ac025a0
Update README.md 2018-10-23 05:59:11 -07:00
Zack 3a53b572f4
Update README.md 2018-10-23 05:58:37 -07:00
Zack 8ae342e128
thanks 2018-10-23 05:55:45 -07:00
Zack Scholl 44f482937d update relay 2018-10-23 05:37:46 -07:00
Zack 8d43a1f63a
Merge pull request #105 from schollz/4.1-sync
4.1 sync
2018-10-23 05:30:59 -07:00
Zack fc38472015
Merge pull request #103 from nicolashardy/patch-1
Improve compression speed
2018-10-23 05:30:28 -07:00
Zack Scholl 61d14be70d add compress test 2018-10-23 05:28:30 -07:00
nicolashardy 20497437fe
Improve compression speed
Use Huffman compression in order to fasten the compression speed as described in https://golang.org/pkg/compress/flate/#NewWriter
2018-10-23 11:05:54 +02:00
Zack Scholl 44af4a8ae3 Merge branch '4.1-sync' of github.com:schollz/croc into 4.1-sync 2018-10-22 20:50:57 -07:00
Zack Scholl 824c49254f update readme 2018-10-22 20:50:36 -07:00
Zack 721567fc72
Create issue_template.md 2018-10-22 20:46:20 -07:00
Zack Scholl 08c84e9f85 connect to tcp in parallel 2018-10-22 20:34:04 -07:00
Zack Scholl edc206e73e fix travis 2018-10-22 20:01:40 -07:00
Zack Scholl c2dd9091ff recipient listens to sender 2018-10-22 19:48:45 -07:00
Zack Scholl e5fcc0d3ee add models 2018-10-22 19:42:39 -07:00
Zack Scholl ea9aa3f8ec recipient websockets should check for errors 2018-10-22 19:41:50 -07:00
Zack Scholl 6a07e1538d sender listens for recipient to close 2018-10-22 19:39:16 -07:00
Zack Scholl ab5df93d10 move reading to goroutine 2018-10-22 19:11:43 -07:00
Zack Scholl db42e96b7e add go111module on 2018-10-22 16:56:19 -07:00
Zack Scholl 3d9bc7193d use latest go 2018-10-22 16:54:57 -07:00
Zack Scholl 3064ceef81 add output folder 2018-10-22 06:36:36 -07:00
Zack Scholl 47931d6ba2 update readme 2018-10-21 11:34:31 -07:00
Zack Scholl 3dc6d44c41 throw error if versions are incompatible 2018-10-21 10:46:04 -07:00
Zack Scholl 380ecc7ff9 update gomod 2018-10-21 10:33:15 -07:00
Zack Scholl 708e6fab8b fix imports 2018-10-21 10:06:14 -06:00
Zack Scholl 45b7eebbb9 use normal import 2018-10-21 09:05:27 -07:00
Zack Scholl 69b19c7e78 recipient also uses codephrase 2018-10-21 08:25:53 -07:00
Zack Scholl dd03cdc6e3 update readme about config file 2018-10-21 08:23:56 -07:00
Zack Scholl 81bc06eabb add configuration file 2018-10-21 08:21:58 -07:00
Zack Scholl 1ae117166a add config default 2018-10-21 07:54:59 -07:00
Zack Scholl 0d17219c87 add initial struct fixes #98 2018-10-21 07:45:05 -07:00
Zack Scholl 9e7661c1b0 update deps 2018-10-21 07:43:45 -07:00
Zack Scholl ace9b35e34 remove utils dependency 2018-10-21 07:38:11 -07:00
Zack Scholl 7371f6f238 remove utils dependency 2018-10-21 07:38:04 -07:00
Zack Scholl 23d451540c update cli 2018-10-21 07:33:29 -07:00
Zack Scholl e591c6afb6 better error message when interrupting 2018-10-21 07:31:35 -07:00
Zack Scholl 9349496111 recipient sends back initial data 2018-10-21 07:25:43 -07:00
Zack Scholl 6e10ed25af recipient sends errors through websockets 2018-10-21 07:23:48 -07:00
Zack Scholl d05e196139 return errors through websockets 2018-10-21 07:20:23 -07:00
Zack Scholl 304355af48 update pake 2018-10-21 07:10:36 -07:00
Zack 50a64d04da
Update README.md 2018-10-20 07:14:36 -07:00
Zack Scholl 4aab058344 add windows icon 2018-10-20 07:02:51 -07:00
Zack Scholl 06e8260e50 bump version 2018-10-19 10:35:54 -07:00
Zack Scholl dc6493374a open folder if no arguments given 2018-10-19 10:18:49 -07:00
Zack Scholl 5ecbab6673 fix release 2018-10-19 07:54:20 -07:00
Zack Scholl f94790dc75 add release 2018-10-19 07:50:43 -07:00
Zack Scholl 92af0b46ab add release 2018-10-19 07:46:42 -07:00
Zack Scholl 4e55b1efd1 don't do debug 2018-10-19 07:33:08 -07:00
Zack Scholl 0e4fff7378 open folder after receiving 2018-10-19 07:30:24 -07:00
Zack Scholl 79f7e9af41 add icons 2018-10-19 07:25:22 -07:00
Zack Scholl 62bf674365 add more info to win 2018-10-19 06:36:45 -07:00
Zack Scholl 2fc216cb1b bump 2018-10-18 09:35:51 -07:00
Zack Scholl ec148d98c1 make sure recipient connects to TCP first 2018-10-18 09:35:08 -07:00
Zack Scholl 365eca9653 update goreleaser 2018-10-18 07:54:25 -06:00
Zack Scholl 987a21fb8f bump version 2018-10-18 07:53:06 -06:00
Zack Scholl e85eaac9e3 add parent window 2018-10-18 06:45:32 -07:00
Zack Scholl 366d3c527c fix fprintf 2018-10-18 06:40:24 -07:00
Zack Scholl 3b498d57cf switch to window 2018-10-18 06:36:16 -07:00
Zack Scholl 82e274875d fix zipping on windows 2018-10-18 06:34:48 -07:00
Zack Scholl e47393031b bump version 2018-10-17 23:14:46 -06:00
Zack Scholl 4d35b3a397 reduce goreleaser 2018-10-17 23:11:02 -06:00
Zack Scholl 48933b5ecc better ui for window 2018-10-17 21:38:29 -07:00
Zack Scholl f9dfa6bc05 add window recipient prompt 2018-10-17 18:14:45 -07:00
Zack Scholl 4ee008225e add makefile for the windows version 2018-10-17 16:57:36 -07:00
Zack Scholl 24e0573116 update progressbar 2018-10-17 10:20:09 -07:00
Zack 62e7629466
Merge pull request #94 from schollz/wincroc
Wincroc
2018-10-17 07:55:56 -07:00
Zack Scholl 56e0068129 send file works 2018-10-17 07:41:13 -07:00
Zack Scholl 93942f4e0c give stop signals to servers 2018-10-17 07:38:21 -07:00
Zack Scholl 157ab169aa sending is working for wincroc 2018-10-17 07:01:44 -07:00
Zack Scholl 6a899492f5 add state 2018-10-17 06:39:02 -07:00
Zack Scholl 47ab799c6f add file stats to state 2018-10-17 06:19:01 -07:00
Zack Scholl 55d9137b6d add state 2018-10-17 06:13:38 -07:00
Zack Scholl 3bed0bc8bf move files here 2018-10-17 06:13:38 -07:00
Zack Scholl 8734394bb8 merge sender and recipient into croc 2018-10-17 06:13:38 -07:00
Zack Scholl 0bbf2841ca use build tags 2018-10-16 15:59:04 -07:00
Zack Scholl 144102a721 window based croc 2018-10-16 15:48:22 -07:00
Zack Scholl 9a41d9099b move main to cli 2018-10-16 12:23:01 -07:00
Zack Scholl 49a73d7183 update readme 2018-10-14 16:27:07 -07:00
Zack 76da134a2f
Update README.md 2018-10-14 07:15:47 -07:00
Zack f7487e8589
Update README.md 2018-10-13 11:25:35 -07:00
Zack ad697febf4
Update default.txt 2018-10-13 11:03:15 -07:00
Zack 8662961e93
Update README.md 2018-10-13 10:50:29 -07:00
Zack 28083f3204
Rename install.sh to default.txt 2018-10-13 10:46:39 -07:00
Zack da94e54d7d
Update install.sh 2018-10-13 10:36:32 -07:00
Zack 267134dc6c
Create install.sh 2018-10-13 10:23:16 -07:00
Zack Scholl 9826023f22 update goreleaser 2018-10-13 10:25:39 -06:00
Zack Scholl 09a90a322a add more package support 2018-10-13 10:19:43 -06:00
Zack Scholl 74f0ac5950 bump version 2018-10-13 06:19:10 -07:00
Zack Scholl 2fb21245ab delete old rooms 2018-10-13 06:13:50 -07:00
Zack Scholl cc6edd24d1 connect to TCP as early as possible 2018-10-13 06:09:55 -07:00
Zack Scholl 70fb9b77ca add coverage 2018-10-11 21:34:56 -07:00
Zack e46ac60c1b
bump version 2018-10-11 21:30:05 -07:00
Zack Scholl a63666cf24 run all tests 2018-10-11 15:32:19 -07:00
Zack Scholl 81bc14f29b multiplex 8 tcp ports 2018-10-11 10:55:46 -07:00
Zack 6fc7b9b2d6
update badges 2018-10-11 07:33:35 -07:00
Zack 0f0b6c5b29
Update README.md 2018-10-11 07:31:10 -07:00
Zack Scholl af11143cba suppress logging messages when ctl+c interrupting
update readme
2018-10-11 06:51:03 -07:00
Zack Scholl f9b79ed371 add gifs
update readme
2018-10-10 06:57:06 -07:00
Zack Scholl 91e065529b fix timeout 2018-10-09 21:17:51 -07:00
Zack Scholl 42344a4c6e fix corruption 2018-10-09 21:17:51 -07:00
Zack Scholl d1e1694631 more debug 2018-10-09 21:17:47 -07:00
Zack Scholl 9d2f07f478 copy tcp writing into byte array 2018-10-09 21:17:47 -07:00
Zack Scholl b0164920c7 increase timeout 2018-10-09 21:17:47 -07:00
Zack Scholl 8d1783fdc3 update logo 2018-10-09 21:17:43 -07:00
Zack Scholl 6955f19439 recipient can easily stop now 2018-10-09 19:01:50 -07:00
Zack Scholl 9439b8ea2d update deps 2018-10-09 17:13:37 -07:00
Zack Scholl d50c8f271f remove created zip directory after finish 2018-10-09 17:11:54 -07:00
Zack Scholl 3984aaeee2 remove file if overwriting 2018-10-09 16:50:18 -07:00
Zack Scholl 71ba80cee0 zip without chdir 2018-10-09 16:40:03 -07:00
Zack Scholl 9335aca877 fix file descriptor 2018-10-09 07:03:33 -07:00
Zack Scholl edda09df00 fix file descriptor 2018-10-09 07:03:06 -07:00
Zack 5b5c05d694
Merge pull request #90 from schollz/resume
Resume
2018-10-09 06:59:06 -07:00
Zack Scholl c600b51888 resume works with websockets or tcp 2018-10-09 06:56:38 -07:00
Zack Scholl e18938fb70 change name of croc zip 2018-10-09 06:33:25 -07:00
Zack Scholl 9940856317 rearrange block communication 2018-10-09 06:32:49 -07:00
Zack Scholl 61d57ad0af sender and recipient share blocks 2018-10-09 06:01:21 -07:00
Zack Scholl 66a37ae5b2 reduce number of packets 2018-10-09 04:50:38 -07:00
Zack Scholl fdfa7f209d revert to da2b22f 2018-09-26 14:31:45 -07:00
Zack Scholl bc4bd2b0a8 don't use writer 2018-09-26 11:11:19 -07:00
Zack Scholl 8ddd7aff06 flush once 2018-09-26 11:07:17 -07:00
Zack Scholl cc0ef58b9f use netconn 2018-09-26 10:54:11 -07:00
Zack Scholl 21cfcc0bc2 use netconn 2018-09-26 10:53:47 -07:00
Zack Scholl 928b28dc80 use netconn 2018-09-26 10:51:28 -07:00
Zack Scholl fecc8d5897 use netconn 2018-09-26 10:46:36 -07:00
Zack Scholl 420d2be271 use netconn 2018-09-26 10:43:38 -07:00
Zack Scholl 1261a16b55 try fix 2018-09-26 10:09:11 -07:00
Zack Scholl 558d9133a6 try fix 2018-09-26 10:03:13 -07:00
Zack Scholl 267056b3fd try fix 2018-09-26 09:55:14 -07:00
Zack Scholl 4e3138e099 try fix 2018-09-26 09:48:11 -07:00
Zack Scholl a6b33fe046 try fix 2018-09-26 09:45:36 -07:00
Zack Scholl ecf8cbcdda try fix 2018-09-26 09:42:45 -07:00
Zack Scholl f6e2560742 try fix 2018-09-26 09:41:12 -07:00
Zack Scholl ea7ed1a2db try fix 2018-09-26 09:40:40 -07:00
Zack Scholl e92c7f15f1 try fix 2018-09-26 09:39:18 -07:00
Zack Scholl 3fc8edfef9 try fix 2018-09-26 09:38:37 -07:00
Zack Scholl 089d2bbe1a try fix 2018-09-26 09:36:25 -07:00
Zack Scholl 0bd4a0ac75 try fix 2018-09-26 09:27:36 -07:00
Zack Scholl 7a961ecffd try fix 2018-09-26 09:26:44 -07:00
Zack Scholl d2a708eaaa try fix 2018-09-26 09:24:40 -07:00
Zack Scholl b573f5c853 try fix 2018-09-26 09:23:07 -07:00
Zack Scholl 1049e9c8c8 try fix 2018-09-26 09:20:20 -07:00
Zack Scholl 113452d459 try fix 2018-09-26 09:14:24 -07:00
Zack Scholl 1954691f44 try fix 2018-09-26 09:13:11 -07:00
Zack Scholl 182a9fe2f4 try fix 2018-09-26 09:12:38 -07:00
Zack Scholl 42c0240e50 try fix 2018-09-26 09:11:36 -07:00
Zack Scholl 73d8eadce4 try fix 2018-09-26 08:54:01 -07:00
Zack Scholl c0e9d478e7 try fix 2018-09-26 08:46:12 -07:00
Zack Scholl 82b0d2d4c0 use tcpconn 2018-09-26 07:53:46 -07:00
Zack Scholl ab70b53998 use writers in relay 2018-09-26 07:41:07 -07:00
Zack Scholl 085dd4e4c3 implement readers and writers all around 2018-09-26 07:39:45 -07:00
Zack Scholl ea548f290c increase size 2018-09-26 06:57:52 -07:00
Zack Scholl 1a7b123519 increase size 2018-09-26 06:53:46 -07:00
Zack Scholl ae13f82c9e increase size 2018-09-26 06:53:01 -07:00
Zack Scholl f483a6ab9c increase size 2018-09-26 06:51:34 -07:00
Zack Scholl 02196654d9 update 2018-09-26 06:49:39 -07:00
Zack Scholl 7d5d7e6cfb update 2018-09-26 06:48:07 -07:00
Zack Scholl 082dcd2037 revert 2018-09-26 06:44:07 -07:00
Zack Scholl 62d9d74753 increase buffer 2018-09-26 06:43:31 -07:00
Zack Scholl f2f1b31fbc increase buffer size 2018-09-26 06:39:26 -07:00
Zack Scholl 397ceea34c revert 2018-09-26 06:36:47 -07:00
Zack Scholl 0b3d19a52e optimize relay 2018-09-26 06:35:51 -07:00
Zack Scholl da2b22f73d less printing 2018-09-25 19:49:05 -07:00
Zack Scholl 5a94062171 whoops 2018-09-25 19:29:33 -07:00
Zack Scholl a59399630d fixes 2018-09-25 19:25:27 -07:00
Zack f555dc8dbf
Merge pull request #88 from schollz/magic
Magic
2018-09-25 18:58:04 -07:00
Zack Scholl 162b12f42b don't need this anymore 2018-09-25 18:56:36 -07:00
Zack Scholl efa66f7cbe better marshaling 2018-09-25 18:38:19 -07:00
Zack Scholl 7f0b919b0b fix bar 2018-09-25 18:25:12 -07:00
Zack Scholl c8c532c5dd small fix 2018-09-25 17:24:06 -07:00
Zack Scholl 71fee31da0 TCP ports use lots 2018-09-25 17:18:43 -07:00
Zack Scholl ec5d45307a seems to work, with problems 2018-09-25 17:09:45 -07:00
Zack Scholl 02e8021735 fix recipient 2018-09-25 16:14:41 -07:00
Zack Scholl 667edd0373 multiple tcp ports 2018-09-25 15:14:58 -07:00
Zack Scholl a7b8488040 use all procs 2018-09-25 12:33:51 -07:00
Zack Scholl 7fea858252 update deps 2018-09-25 12:26:32 -07:00
Zack Scholl 68896f6ef7 use all cpu 2018-09-25 12:11:36 -07:00
Zack Scholl f62459e1a4 move reading to goroutine 2018-09-25 09:55:35 -07:00
Zack Scholl 75f7cdcf65 introduce magic bytes to stop 2018-09-25 09:39:18 -07:00
Zack Scholl ee7518c7bd use best compression 2018-09-25 09:27:32 -07:00
Zack Scholl 02e63b6473 make faster 2018-09-25 09:17:23 -07:00
Zack Scholl 196c9253b8 use best compression 2018-09-25 07:31:21 -07:00
Zack Scholl 1a22d37c2d do compression in thread 2018-09-25 07:29:55 -07:00
Zack Scholl f169b12109 simplify test 2018-09-24 16:16:33 -07:00
Zack Scholl 44fad198e7 close correctly 2018-09-24 16:10:04 -07:00
Zack Scholl 7df06272b8 make sure to close connection 2018-09-24 16:05:34 -07:00
Zack Scholl f56d5c797c use enc/comp in test 2018-09-24 13:24:18 -07:00
Zack Scholl 7147980eac encryption faster with simpler marshaling 2018-09-24 12:52:19 -07:00
Zack Scholl 8bfbe36dd9 do minimal compression 2018-09-24 12:41:35 -07:00
Zack Scholl 2f47dd3178 disable compression/enc 2018-09-24 12:21:38 -07:00
Zack Scholl d0e75370b2 allow force web 2018-09-24 10:01:30 -07:00
Zack Scholl 6635c84f70 raise tcp size 2018-09-24 09:36:48 -07:00
Zack Scholl 15ecc73f67 update deps 2018-09-24 08:36:24 -07:00
Zack Scholl 7891f27b62 fix test 2018-09-24 08:35:24 -07:00
Zack Scholl f6c2382c0a fix 2018-09-24 08:32:17 -07:00
Zack Scholl 26f0fc3319 ok windows seems to work now 2018-09-24 08:29:54 -07:00
Zack Scholl 5397634217 works on linux? 2018-09-24 07:51:56 -07:00
Zack Scholl 02f4b08929 not working dunno why 2018-09-24 07:51:24 -07:00
Zack Scholl 55b1fa35e4 add both tests 2018-09-24 07:29:44 -07:00
Zack Scholl b202682596 local relay runs with tcp port too 2018-09-24 07:26:52 -07:00
Zack Scholl b14f1c35a3 disable broadcast 2018-09-24 07:24:59 -07:00
Zack Scholl e10789b558 allow forcing using websockets 2018-09-24 07:17:35 -07:00
Zack Scholl 80d48d45d5 test works 2018-09-24 07:06:55 -07:00
Zack Scholl e8ef8e1c61 add test 2018-09-24 07:00:48 -07:00
Zack Scholl 90b08abf39 allow discovering self 2018-09-24 06:49:26 -07:00
Zack Scholl e6b9655387 add benchmark 2018-09-24 06:13:43 -07:00
Zack Scholl 50c29e7334 simplify 2018-09-24 06:10:31 -07:00
Zack Scholl 711f8dfeec improve comm 2018-09-23 19:24:57 -07:00
Zack Scholl ba20bb63ca fix again 2018-09-23 18:00:00 -06:00
Zack Scholl 45fe9b422d fiX 2018-09-23 18:00:00 -06:00
Zack Scholl 975bab61fb make tcp optional 2018-09-23 18:00:00 -06:00
Zack Scholl b7c447473d change buffer size 2018-09-23 18:00:13 -06:00
Zack Scholl 73c33ebe02 fix sending 2018-09-23 18:00:00 -06:00
Zack Scholl fe38107c42 no log 2018-09-23 18:00:00 -06:00
Zack Scholl 7651ed0562 don't count empty bytes 2018-09-23 18:00:09 -06:00
Zack Scholl 2ebe3c1328 update read 2018-09-23 18:00:00 -06:00
Zack Scholl 47fe8a2116 don't count empty bytes 2018-09-23 18:00:00 -06:00
Zack Scholl a8c0c02755 add read deadline 2018-09-23 18:00:00 -06:00
Zack Scholl 8fab2299a1 change buffer size 2018-09-23 18:00:00 -06:00
Zack Scholl 4f9532b761 remove old comments 2018-09-23 18:00:00 -06:00
Zack Scholl da9634c949 change buffer size 2018-09-23 18:00:05 -06:00
Zack Scholl b2939a0452 fix websocket address 2018-09-23 18:00:00 -06:00
Zack Scholl 2788a4e742 communicate tcp port to sender/receiver 2018-09-23 18:00:00 -06:00
Zack Scholl 384de31c5a allow TCP connections as alternative 2018-09-23 18:00:00 -06:00
Zack Scholl 177612f112 update buffer 2018-09-23 18:00:00 -06:00
Zack Scholl 2f800f1de3 add buffer size 2018-09-23 18:00:00 -06:00
Zack Scholl 6c94ece008 remote gitignore 2018-09-23 18:00:00 -06:00
Zack Scholl 8797d35fa1 use single variable for buffer size 2018-09-23 18:00:00 -06:00
Zack Scholl c9dab1ca44 gather file info async, encrypt file info 2018-09-23 18:00:00 -06:00
Zack Scholl 76cb610ffd exchange IP addresses 2018-09-23 18:00:00 -06:00
Zack Scholl d860fe1e9e better ui handling with spinner 2018-09-23 18:00:00 -06:00
Zack Scholl 8afc75f1fc listen for interrupt in websockets 2018-09-23 18:00:00 -06:00
Zack Scholl 0a0c0bfd32 send local/public status 2018-09-23 18:00:00 -06:00
Zack Scholl f3df177ba2 functions to get local/public IP 2018-09-23 18:00:00 -06:00
Zack Scholl 7799d2fb58 use spinner fork 2018-09-23 18:00:00 -06:00
Zack Scholl 3847ba2bb1 update readme 2018-09-22 11:21:44 -07:00
Zack Scholl 232f3375b1 only compress if its not a directory 2018-09-22 10:59:45 -07:00
Zack Scholl c6374da410 toggle encryption/compression 2018-09-22 11:57:04 -06:00
Zack Scholl f977ac24c4 add is compressed/encrypted to filestats 2018-09-22 11:57:18 -06:00
Zack Scholl 1f64d1c93a check if discovered is valid 2018-09-22 11:57:04 -06:00
Zack Scholl edfb018ae2 fix go.mod 2018-09-22 11:57:04 -06:00
Zack Scholl 9a33954d42 travis just test build 2018-09-22 11:57:04 -06:00
Zack Scholl 10111b92cd spinner should be in stderr 2018-09-22 11:57:04 -06:00
Zack Scholl e13f8e7067 allow stdout 2018-09-22 11:57:04 -06:00
Zack Scholl 1acbe9c475 relay log more 2018-09-22 11:57:04 -06:00
Zack Scholl 73791a4dc7 change buffer size 2018-09-22 11:57:04 -06:00
Zack Scholl b469d5db4b increase write wait 2018-09-22 11:57:15 -06:00
Zack Scholl 2946922fb5 use direct address 2018-09-22 11:57:04 -06:00
Zack Scholl 742a935ea9 don't wait for ok 2018-09-22 11:57:11 -06:00
Zack Scholl 54b22cd732 increase buffer 2018-09-22 11:57:08 -06:00
Zack Scholl 9cf6bdf4a8 move file processing until after recipient chimes in 2018-09-22 11:57:04 -06:00
Zack Scholl 4d9455c24b add no prompt option 2018-09-22 11:57:04 -06:00
Zack Scholl 7513702e9c add transfer complete 2018-09-22 11:57:04 -06:00
Zack Scholl 66eeab25fb better spinner 2018-09-22 11:57:04 -06:00
Zack Scholl 82315ca413 recipient use public OR local 2018-09-22 11:57:04 -06:00
Zack Scholl cd3a936795 add recipient finish line 2018-09-22 11:57:04 -06:00
Zack Scholl b1aeedb107 tell server no 2018-09-22 11:57:04 -06:00
Zack Scholl 6d9c829579 prompt user if its okay to receive file 2018-09-22 11:57:04 -06:00
Zack Scholl 1add7e94c9 get receive code if empty 2018-09-22 11:57:04 -06:00
Zack Scholl e5b3e6e06e change default port 2018-09-22 11:57:04 -06:00
Zack Scholl 9d537c42e5 move flags 2018-09-22 11:57:04 -06:00
Zack Scholl f709df4d3e show spinner 2018-09-22 11:57:04 -06:00
Zack Scholl 55bd83576a show text 2018-09-22 11:57:04 -06:00
Zack Scholl 91532085c7 add more text 2018-09-22 11:57:04 -06:00
Zack Scholl f3eb85dd95 add randome name 2018-09-22 11:57:04 -06:00
Zack Scholl ebac8beaaa use stderr for output 2018-09-22 11:57:04 -06:00
Zack Scholl d555a81d30 generate code phrase if not prompted 2018-09-22 11:57:04 -06:00
Zack Scholl 40672a4eaa update readme 2018-09-22 11:57:04 -06:00
Zack Scholl 0528bb22ea determine room from first three chars of codephrase 2018-09-22 11:57:04 -06:00
Zack Scholl 4fd172b6fc fix getting hash 2018-09-22 11:57:04 -06:00
Zack Scholl 6911848141 zip should accomodate relative links 2018-09-22 11:57:04 -06:00
Zack Scholl 9af7c05dc6 remove the zip file if not debug 2018-09-22 11:57:04 -06:00
Zack Scholl c4cfa9b07f unzip in current location 2018-09-22 11:57:04 -06:00
Zack Scholl 11ab8a8078 written file should onlybe name 2018-09-22 11:57:04 -06:00
Zack Scholl a225a08dbc add exists 2018-09-22 11:57:04 -06:00
Zack Scholl 80471c7d02 hash the sent name 2018-09-22 11:56:59 -06:00
Zack Scholl f9ed7553af use sent name 2018-09-21 21:55:07 -07:00
Zack Scholl 83f199b213 add zipping to sending 2018-09-21 21:52:29 -07:00
Zack Scholl 5bf4ff1866 add dirname 2018-09-21 21:50:30 -07:00
Zack Scholl caf5511805 add zipping 2018-09-21 21:50:20 -07:00
Zack Scholl b6b6b754c9 don't show error on 1005 2018-09-21 21:40:39 -07:00
Zack Scholl 24493cf7f5 add peer discovery 2018-09-21 21:35:33 -07:00
Zack Scholl 828f83601d fix hash file 2018-09-21 21:13:46 -07:00
Zack Scholl 274fab92a1 fixes so it works (basically) 2018-09-21 20:51:43 -07:00
Zack Scholl b9dad87526 completely rewrite 2018-09-21 20:17:57 -07:00
Zack 6af10ad871
Update README.md 2018-09-12 07:34:00 -07:00
Zack Scholl 87a17fb9e6 add go.mod 2018-09-07 08:33:39 -06:00
Zack Scholl 53e0585f21 bar finish in wrong spot 2018-07-10 13:59:44 -07:00
Zack Scholl b8f647291a increase timeouts 2018-07-10 08:43:54 -07:00
Zack Scholl 53db42fe5f update ui 2018-07-07 10:08:55 -07:00
Zack Scholl 2081b4e17e remove croc gen 2018-07-07 10:08:18 -07:00
Zack Scholl 9e02fa746c use to/from slash 2018-07-07 10:08:18 -07:00
Zack Scholl ffbc607303 receive argument override 2018-07-07 10:08:18 -07:00
Zack Scholl c01bc56079 wait longer on an abnormal finish 2018-07-07 10:08:18 -07:00
Zack Scholl d906630f3a try to cleanup files 2018-07-07 10:08:18 -07:00
Zack Scholl 085550c94b add newspace 2018-07-07 10:08:18 -07:00
Zack Scholl 0c920a27ab implement dynamic hash 2018-07-07 10:08:17 -07:00
Zack Scholl db50a7eee0 add bytes to progress bar 2018-07-07 10:08:17 -07:00
Zack Scholl 68d42cdadd show spinners 2018-07-07 10:08:17 -07:00
Zack Scholl 2ce63b5cda add spinner for recipient 2018-07-07 10:08:17 -07:00
Zack Scholl 11566c710d fix bug in relay which couldn't handle regular http requests 2018-07-07 10:08:17 -07:00
Zack Scholl 4e88975ed4 use best speed 2018-07-07 10:08:17 -07:00
Zack Scholl 09a16cacd5 remove partially sent files 2018-07-07 10:08:17 -07:00
Zack Scholl 34d499127d add routine to generate key to main utility 2018-07-07 10:08:17 -07:00
Zack Scholl 52ab6be29a update readme 2018-07-07 10:08:17 -07:00
Zack Scholl 02e6aa6ec7 add gifs to readme 2018-07-07 10:08:17 -07:00
Zack Scholl 9c22753ae4 add gifs 2018-07-07 10:08:17 -07:00
Zack Scholl 594029891e don't print 2018-07-07 10:08:17 -07:00
Zack Scholl 280faf7657 implement HEAD request 2018-07-07 10:08:17 -07:00
Zack Scholl 846e3d5d00 show the transfer rate 2018-07-07 10:08:16 -07:00
Zack Scholl 967d3d7c56 add goreleaser 2018-07-07 10:08:16 -07:00
Zack Scholl f2646eb8b3 update readme 2018-07-07 10:08:16 -07:00
Zack Scholl bba0bca15e update readme 2018-07-07 10:08:16 -07:00
Zack Scholl 8373e374cd discover faster 2018-07-07 10:08:16 -07:00
Zack Scholl 80c129b411 default to https ws 2018-07-07 10:08:16 -07:00
Zack Scholl efee59f541 check meta data for decryption flag 2018-07-07 10:08:16 -07:00
Zack Scholl 7be11a6fda flag is no compress 2018-07-07 10:08:16 -07:00
Zack Scholl bc34811750 encrypt only if flagged 2018-07-07 10:08:16 -07:00
Zack Scholl ba3fa6ffce Make sure to remove croc-stdin 2018-07-07 10:08:16 -07:00
Zack Scholl a1611ccc88 don't broadcast channel 2018-07-07 10:08:16 -07:00
Zack Scholl 0ec32e3f9a clean up after local file transfer 2018-07-07 10:08:16 -07:00
Zack Scholl 551160d601 always require code 2018-07-07 10:08:16 -07:00
Zack Scholl 7f423cda26 fix address bug 2018-07-07 10:08:16 -07:00
Zack Scholl 91c95a5a8c fix address bug 2018-07-07 10:08:16 -07:00
Zack Scholl 22220e54a7 use correct local ip if sending locally 2018-07-07 10:08:16 -07:00
Zack Scholl a6bc4973aa update readme 2018-07-07 10:08:15 -07:00
Zack Scholl f315a0bb79 add stdin 2018-07-07 10:08:15 -07:00
Zack Scholl ebad469554 cleanup after returning 2018-07-07 10:08:15 -07:00
Zack Scholl d255f3bba0 stdout 2018-07-07 10:08:15 -07:00
Zack Scholl 909e82323d stdout 2018-07-07 10:08:15 -07:00
Zack Scholl 1ceed5de35 stdout 2018-07-07 10:08:15 -07:00
Zack Scholl 0539e425d2 stdout 2018-07-07 10:08:15 -07:00
Zack Scholl b09955561f print other 2018-07-07 10:08:15 -07:00
Zack Scholl 5ca6a6455e print other 2018-07-07 10:08:15 -07:00
Zack Scholl 2e545e6594 add no-local 2018-07-07 10:08:15 -07:00
Zack Scholl 51f3de95a7 fix bug 2018-07-07 10:08:15 -07:00
Zack Scholl f4d607a4cf fix bug 2018-07-07 10:08:15 -07:00
Zack Scholl bc5f4b7131 fix bug 2018-07-07 10:08:15 -07:00
Zack Scholl 5a21ff6729 update 2018-07-07 10:08:15 -07:00
Zack Scholl 66e510f735 compute addresses 2018-07-07 10:08:15 -07:00
Zack Scholl 6164bc37d5 compute addresses 2018-07-07 10:08:15 -07:00
Zack Scholl ca9fafed55 compute addresses 2018-07-07 10:08:14 -07:00
Zack Scholl 3d24c0e258 compute addresses 2018-07-07 10:08:14 -07:00
Zack Scholl 816c25b05b compute addresses 2018-07-07 10:08:14 -07:00
Zack Scholl 43026b9c2e compute addresses 2018-07-07 10:08:14 -07:00
Zack Scholl b7f40b2181 fix parameters 2018-07-07 10:08:14 -07:00
Zack Scholl dd8d8ee4ce improve relay 2018-07-07 10:08:14 -07:00
Zack Scholl e055918656 move pake to library 2018-07-07 10:08:14 -07:00
Zack Scholl 1223b3e51d specify relay ports 2018-07-07 10:08:14 -07:00
Zack Scholl ae7ceca3b7 add siec as default 2018-07-07 10:08:14 -07:00
Zack Scholl f6abf9c4e8 use siec 2018-07-07 10:08:14 -07:00
Zack Scholl a9969b161f use elliptic curve interface 2018-07-07 10:08:14 -07:00
Zack Scholl d1d5b02f27 copy over info 2018-07-07 10:08:14 -07:00
Zack Scholl 0d71cde941 carry over file info 2018-07-07 10:08:14 -07:00
Zack Scholl bf7a1bbdff discovering 2018-07-07 10:08:14 -07:00
Zack Scholl 1cdbdcb08e fix bug 2018-07-07 10:08:13 -07:00
Zack Scholl 2b61224707 fix bug 2018-07-07 10:08:13 -07:00
Zack Scholl bda038b8fc add testing data 2018-07-07 10:08:13 -07:00
Zack Scholl 1d316e6fbe add peer discovery 2018-07-07 10:08:13 -07:00
Zack Scholl b2885a7d95 add peer discovery 2018-07-07 10:08:13 -07:00
Zack Scholl 2c444ad400 add peer discovery 2018-07-07 10:08:13 -07:00
Zack Scholl f7c22067d4 add peer discovery 2018-07-07 10:08:13 -07:00
Zack Scholl aa0c5acc60 add basic ui 2018-07-07 10:08:13 -07:00
Zack Scholl d95c90de44 building the ui 2018-07-07 10:08:13 -07:00
Zack Scholl f1b62ea30d check if file exists 2018-07-07 10:08:13 -07:00
Zack Scholl 0d5836b4e8 fix zipping 2018-07-07 10:08:13 -07:00
Zack Scholl adff8400be not quite working 2018-07-07 10:08:13 -07:00
Zack Scholl 919de910cb update models 2018-07-07 10:08:13 -07:00
Zack Scholl 837a66e975 fix options 2018-07-07 10:08:13 -07:00
Zack Scholl fa1b2af314 works 2018-07-07 10:08:13 -07:00
Zack Scholl eb3251a93f lock websockets 2018-07-07 10:08:12 -07:00
Zack Scholl 0ab25185d3 reorganized files 2018-07-07 10:08:12 -07:00
Zack Scholl 59fc697b4f add zip file 2018-07-07 10:08:12 -07:00
Zack Scholl 6e27bfebdd receiving file works 2018-07-07 10:08:12 -07:00
Zack Scholl 98374c31cd file stuff ready 2018-07-07 10:08:12 -07:00
Zack Scholl 0bf384dd82 file transfer ready 2018-07-07 10:08:12 -07:00
Zack Scholl 72e2d4d3d8 pake works between two clients 2018-07-07 10:08:12 -07:00
Zack Scholl f6751dadb9 add pake 2018-07-07 10:08:12 -07:00
Zack Scholl 283bf704a2 todo: make big.Ints part of channelData 2018-07-07 10:08:12 -07:00
Zack Scholl f64427f70d simplify setup 2018-07-07 10:08:12 -07:00
Zack Scholl 7d07ccfe40 update the secret variables 2018-07-07 10:08:12 -07:00
Zack Scholl 87c935dc1e update the curve in client 2018-07-07 10:08:12 -07:00
Zack Scholl b32d7060bf sender + receiver mildly working 2018-07-07 10:08:11 -07:00
Zack Scholl 22cd0afd11 websockets working 2018-07-07 10:08:11 -07:00
Zack Scholl 7a1f0f66cd consolidate structures 2018-07-07 10:08:11 -07:00
Zack Scholl 6f1e6f3da8 move to websockets 2018-07-07 10:08:11 -07:00
Zack Scholl ffebb472b9 remove globals 2018-07-07 10:08:11 -07:00
Zack Scholl b2dc1f32f8 cleanup dangling channels 2018-07-07 10:08:11 -07:00
Zack Scholl e3ebed186d update travis 2018-07-07 10:08:11 -07:00
Zack Scholl e557869afd simplified api 2018-07-07 10:08:11 -07:00
Zack Scholl 7656b102c7 add crypto, utils 2018-07-07 10:08:11 -07:00
Zack Scholl ce8135002c add api and divide into relay+server 2018-07-07 10:08:11 -07:00
Zack Scholl 5ede3186e5 first attempt 2018-07-07 10:08:11 -07:00
Zack Scholl 84f732b662 start over 2018-07-07 10:08:10 -07:00
Zack 606918b14e Update README.md 2018-07-07 10:08:10 -07:00
Zack 3335250e92 Update README.md 2018-07-07 10:08:10 -07:00
Zack Scholl 778e8dda4d new gifs 2018-07-07 10:08:10 -07:00
Zack 3bab088f98 Update README.md 2018-07-07 10:08:10 -07:00
Zack Scholl 0ccc2685cf fix erroring 2018-06-27 07:46:51 -06:00
Zack Scholl db911d1bce fix spelling 2018-06-26 21:46:23 -07:00
Zack Scholl 2b8d8670bd update readme 2018-06-26 21:43:29 -07:00
Zack Scholl af92a47450 update readme 2018-06-26 21:41:59 -07:00
Zack Scholl fc7dcc5e0a fix spaces 2018-06-26 21:10:19 -07:00
Zack Scholl 44c08329fb vendor 2018-06-26 22:04:45 -06:00
Zack Scholl e438b0a270 tofu 2018-06-26 20:57:23 -07:00
Zack Scholl f3523ebf36 use hash words 2018-06-26 20:40:16 -07:00
Zack Scholl 1866b610fd consolidate main files 2018-06-26 20:32:54 -07:00
Zack Scholl 277e187abb add colors 2018-06-26 09:09:25 -07:00
Zack Scholl 541ab998bd add no local flag for easy testing 2018-06-26 08:55:30 -07:00
Zack Scholl 07ecef8d87 update vendoring 2018-06-26 08:50:38 -07:00
Zack Scholl 143f3dba14 improve recipient ui 2018-06-26 07:54:05 -07:00
Zack Scholl 13bf5994dc correctly do relative paths in windows 2018-06-26 07:50:14 -07:00
Zack Scholl fa522c3e54 correctly do relative paths in windows 2018-06-26 07:48:11 -07:00
Zack Scholl 6d7911ab24 add spinner 2018-06-26 07:43:22 -07:00
Zack Scholl 3e5aa91f34 re-vendor 2018-06-25 11:59:56 -07:00
Zack Scholl 181de46313 check if can connect first 2018-06-25 08:05:56 -07:00
Zack Scholl 42b9a00102 check if chrooted before using local relay 2018-06-25 07:37:52 -07:00
Zack Scholl c70327ff82 more debugging 2018-06-25 06:47:37 -07:00
Zack Scholl de2de7b75c update ui in readme 2018-06-24 19:34:51 -07:00
Zack Scholl 003aa64d2b update ui 2018-06-24 19:33:27 -07:00
Zack Scholl c5b7ba0905 change placement of public key 2018-06-24 19:29:25 -07:00
Zack Scholl e084186b5e save the keypair in ~/.config/croc 2018-06-24 19:21:56 -07:00
Zack Scholl 5ca9b06eb7 don't need to double public address 2018-06-24 10:31:04 -07:00
Zack Scholl 13670d683c finish bar 2018-06-24 10:13:58 -07:00
Zack Scholl 97f99e60f2 if sending with pipes, force yes 2018-06-24 07:44:25 -07:00
Zack Scholl ba3accb9d7 fix travis.yml 2018-06-24 07:36:46 -07:00
Zack Scholl 44e169464c fix travis.yml 2018-06-24 07:34:53 -07:00
Zack Scholl 0e99540655 move debug up 2018-06-24 07:32:32 -07:00
Zack Scholl 9746014f0b remove dirs after encoding 2018-06-24 07:30:35 -07:00
Zack Scholl 04dc07913e re-vendor 2018-06-24 08:23:05 -06:00
Zack Scholl a29a7e2f04 add back testingdata 2018-06-24 07:18:02 -07:00
Zack Scholl 83f9005a1d update travis 2018-06-24 07:16:29 -07:00
Zack Scholl 9acaa988ae update readme 2018-06-24 07:12:59 -07:00
Zack Scholl 26ef99c170 add back receiver bar 2018-06-24 07:11:42 -07:00
Zack Scholl b3847798a4 update travis 2018-06-24 07:00:52 -07:00
Zack 88c2fcea0b
Merge pull request #72 from schollz/v2
V2
2018-06-24 06:58:57 -07:00
Zack Scholl de7e2a6885 v2 2018-06-24 06:58:27 -07:00
Zack Scholl 992e109279 fix bugs in relay 2018-06-24 06:55:43 -07:00
Zack Scholl cc79aaeecb fix broadcast 2018-06-24 06:18:48 -07:00
Zack Scholl 67bceee220 fix broadcast 2018-06-24 06:16:52 -07:00
Zack Scholl 3c22789e3b fix broadcast 2018-06-24 06:15:58 -07:00
Zack Scholl 6c3bb17d7c use newest version of prgressbar 2018-06-24 06:14:07 -07:00
Zack Scholl 7c06c56700 check for discover errors 2018-06-23 11:08:02 -07:00
Zack Scholl 901b0af827 show code 2018-06-23 11:03:44 -07:00
Zack Scholl 6e69b2760e require mutual consent 2018-06-23 10:57:25 -07:00
Zack Scholl 51a87f1110 fix bug 2018-06-23 10:02:46 -07:00
Zack Scholl 30c9c3317f use keypair to validate 2018-06-23 09:18:35 -07:00
Zack 60e31803c9
improve readme 2018-06-22 06:13:04 -07:00
Zack cd26b2437d
Update README.md 2018-05-05 14:11:09 -07:00
Zack c2927ffaee
Update README.md 2018-05-05 14:10:49 -07:00
Zack Scholl 349e3a81c7 Revert "allow relay to overwrite connections"
This reverts commit 4840c33eee.
2018-04-27 15:40:40 -07:00
Zack Scholl 4840c33eee allow relay to overwrite connections 2018-04-27 15:36:57 -07:00
Zack 08319cfd3f
Update README.md 2018-04-25 02:22:43 -07:00
Zack f9c570e942
Update README.md 2018-04-25 02:22:13 -07:00
Zack Scholl 90809a80a1 have --local flag bypass public server 2018-04-25 00:20:09 -07:00
Zack Scholl 7f5e3f50a0 update readme 2018-04-24 23:02:49 -07:00
Zack Scholl ad2ab1d8da show filename + file size early 2018-04-24 22:58:35 -07:00
Zack 488b88f9dd
Merge pull request #67 from schollz/local
automatically discover local
2018-04-24 21:01:36 -07:00
Zack Scholl 346284cbed update dependencies 2018-04-24 20:58:41 -07:00
Zack Scholl 90f1277ee5 automatically determine if local 2018-04-24 20:54:50 -07:00
Zack Scholl 2bd8504a57 works without --local 2018-04-24 07:46:07 -07:00
Zack Scholl bea025fbe4 update readme 2018-04-24 03:21:50 -07:00
Zack Scholl 4e7f50c927 update readme 2018-04-24 00:05:30 -07:00
Zack Scholl 882d63a9c3 update readme 2018-04-24 00:03:07 -07:00
Zack Scholl 9837763bed simplify filepath 2018-04-23 23:45:40 -07:00
Zack Scholl 13a35795be Fix windows bug that adds .\ to filename when its .\X 2018-04-23 23:42:46 -07:00
Zack Scholl bd4eaf90df update dependencies 2018-04-23 23:55:54 -06:00
Zack Scholl f0f7a43888 version 1.0.0 2018-04-23 23:55:54 -06:00
Zack Scholl 0e3ee4c343 Update readme 2018-04-23 23:55:50 -06:00
Zack Scholl 0127df5f04 new version of peerdiscovery to work with windows 2018-04-23 23:55:42 -06:00
Zack Scholl d4fa4bc9c0 add back prompt for code 2018-04-23 23:55:38 -06:00
Zack Scholl e7d2f05399 vendor dependencies 2018-04-23 23:55:37 -06:00
Zack Scholl 091e8aecac update graphics 2018-04-23 23:55:37 -06:00
Zack Scholl 00dfe62033 bug fix for allowing full input of servername 2018-04-23 23:55:37 -06:00
Zack Scholl 67526279ce change timelimit 2018-04-23 23:55:37 -06:00
Zack Scholl 7cea7ea9e2 Add new logging 2018-04-23 23:55:37 -06:00
Zack Scholl 1308694711 better ui 2018-04-23 23:55:37 -06:00
Zack Scholl 638ca9ef27 no need to specify number of connections now 2018-04-23 23:55:33 -06:00
Zack Scholl f0ed13c392 delete vendor for working 2018-04-23 23:55:33 -06:00
Zack Scholl f689ca3909 Fix tarinator for windows 2018-04-23 23:55:29 -06:00
Zack Scholl 1ced0aa532 add debug statement 2018-04-23 23:55:25 -06:00
Zack Scholl 13b7f4afcb dont encrypt for local transfer 2018-04-23 23:55:25 -06:00
Zack Scholl 95bec30262 fix progress bar 2018-04-23 23:55:19 -06:00
Zack Scholl b6df5839b8 Add local option
change local receive code
2018-04-23 23:55:14 -06:00
Zack Scholl c74c9b8faf update ui
update readme
2018-04-23 23:55:09 -06:00
Zack Scholl 22d7a1d42d determine stdin automatically 2018-04-23 23:52:31 -06:00
Zack Scholl 3701240b10 Added new vendoring 2018-04-23 23:52:30 -06:00
Zack Scholl 68b937f4cb Allow auto-receive 2018-04-23 23:52:30 -06:00
Zack Scholl 39e2a20a6f Fix debug progressbar bug and make sure to clean enc.0 2018-04-23 23:52:30 -06:00
Zack Scholl 78df00f7ab Use stderr so stdout can be redirected 2018-04-23 23:52:30 -06:00
Zack Scholl ef03f577f6 Update lockfile 2018-04-23 23:52:30 -06:00
Zack Scholl 774312cb9d update dependencies 2018-04-23 23:52:30 -06:00
Travis 19bfbcb9c2 initial implementation for reading input files from stdin 2018-04-23 23:52:30 -06:00
Zack a35612abfe Update README.md 2018-04-23 23:52:30 -06:00
Zack Scholl 3037385cb6 Update dependencies 2018-04-23 23:52:30 -06:00
Zack Scholl 15f9acc441 gofmt -s -w 2018-04-23 23:52:30 -06:00
smileboywtu 04ef2c4158 add dependency 2018-04-23 23:52:30 -06:00
smileboywtu e1f48721a4 generic way 2018-04-23 23:52:29 -06:00
smileboywtu d518cf0c2b update dependency 2018-04-23 23:52:29 -06:00
smileboywtu d60d81759f use newer version cli 2018-04-23 23:52:29 -06:00
smileboywtu 97857ff4c2 update go dependency 2018-04-23 23:52:29 -06:00
smileboywtu 1eb07db618 add home dir config .croc 2018-04-23 23:52:29 -06:00
Zack 93d0846e30 Update README.md 2018-04-23 23:52:29 -06:00
Zack 743cc2e22e Update README.md 2018-04-23 23:52:29 -06:00
陈博 21a0e1778e use link flag to control version 2018-04-23 23:52:28 -06:00
陈博 63ba167880 update main.go 2018-04-23 23:52:28 -06:00
Zack Scholl 389ecf6e60 Add option to hide logo 2018-04-23 23:52:28 -06:00
Zack Scholl e8d5afe1fa Add cleanup on Ctl+C 2018-04-23 23:52:28 -06:00
陈博 407d85270c fix file split bugs and sending server:port display error 2018-02-07 16:24:44 +08:00
Zack Scholl 33e41b2b0a Todo: move console logo to usage 2017-11-16 10:09:27 -07:00
Zack da9668af19
Update Gifs 2017-11-05 07:20:05 -07:00
Zack Scholl 4779c0ac0a Update README 2017-11-05 07:10:32 -07:00
Zack Scholl 152c27a5e9 Bug fix: remove race condition for startTime 2017-11-05 07:07:35 -07:00
Zack d105c253c1
Update README.md 2017-11-04 05:41:20 -06:00
Zack Scholl 8ff1fe1d2a Bug fix: tarring in Windows and untarring in Linux
Also updated depdencies
2017-11-04 05:38:27 -06:00
Zack Scholl bab9ceb1bb Update progressbar 2017-10-31 05:41:29 -06:00
Zack 4574e4816f
Update README.md 2017-10-30 02:40:01 -06:00
Zack fa2bb39dae
Merge pull request #57 from goggle/update-version-badge
Update version badge in README.md to 0.3.0
2017-10-30 02:39:04 -06:00
Alex Seiler cfad4c8010 Update version badge in README.md to 0.3.0 2017-10-30 02:05:24 +01:00
1170 changed files with 7490 additions and 666441 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,3 @@
# These are supported funding model platforms
github: schollz

31
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,31 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
assignees: ''
---
<!-- The comments between these brackets won't show up in the submitted issue (as you can see in the Preview). -->
<!-- Please try to download latest, https://github.com/schollz/croc/releases/latest of croc before reporting a bug! -->
## Describe the bug
## To Reproduce
Steps to reproduce the behavior:
1.
2.
3.
4.
## Expected behaviour
## Version
## Additional context

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

10
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"

18
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,18 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
unit-tests:
name: Go unit tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.20'
- run: go version
- run: go test -v ./...

64
.github/workflows/deploy.yml vendored Normal file
View File

@ -0,0 +1,64 @@
# This is a basic workflow to help you get started with Actions
name: CD
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches:
- '*'
tags:
- 'v*'
pull_request:
branches:
- '*'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v4
-
name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5
with:
images: schollz/croc
# generate Docker tags based on the following events/attributes
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha
-
name: Set up QEMU
uses: docker/setup-qemu-action@v3
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm,linux/arm64,linux/386
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}

123
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,123 @@
name: Make release
on:
release:
types: [created]
workflow_dispatch:
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout project
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.20'
- name: Build Windows 7
run: |
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags '-extldflags "-static"' -o croc.exe
zip croc_${{ github.event.release.name }}_Windows7-64bit.zip croc.exe
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags '-extldflags "-static"' -o croc.exe
zip croc_${{ github.event.release.name }}_Windows7-32bit.zip croc.exe
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Prepare source tarball
run: |
git clone -b ${{ github.event.release.name }} --depth 1 https://github.com/schollz/croc croc-${{ github.event.release.name }}
cd croc-${{ github.event.release.name }} && go mod tidy && go mod vendor
cd .. && tar -czvf croc_${{ github.event.release.name }}_src.tar.gz croc-${{ github.event.release.name }}
- name: Build files
run: |
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags '-extldflags "-static"' -o croc.exe
zip croc_${{ github.event.release.name }}_Windows-64bit.zip croc.exe LICENSE
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags '-extldflags "-static"' -o croc.exe
zip croc_${{ github.event.release.name }}_Windows-32bit.zip croc.exe LICENSE
CGO_ENABLED=0 GOOS=windows GOARCH=arm go build -ldflags '-extldflags "-static"' -o croc.exe
zip croc_${{ github.event.release.name }}_Windows-ARM.zip croc.exe LICENSE
CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -ldflags '-extldflags "-static"' -o croc.exe
zip croc_${{ github.event.release.name }}_Windows-ARM64.zip croc.exe LICENSE
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags '-extldflags "-static"' -o croc
tar -czvf croc_${{ github.event.release.name }}_Linux-64bit.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags '-extldflags "-static"' -o croc
tar -czvf croc_${{ github.event.release.name }}_Linux-32bit.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags '-extldflags "-static"' -o croc
tar -czvf croc_${{ github.event.release.name }}_Linux-ARM.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags '-extldflags "-static"' -o croc
tar -czvf croc_${{ github.event.release.name }}_Linux-ARM64.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags '-s -extldflags "-sectcreate __TEXT __info_plist Info.plist"' -o croc
tar -czvf croc_${{ github.event.release.name }}_macOS-64bit.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags '-s -extldflags "-sectcreate __TEXT __info_plist Info.plist"' -o croc
tar -czvf croc_${{ github.event.release.name }}_macOS-ARM64.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=dragonfly GOARCH=amd64 go build -ldflags '' -o croc
tar -czvf croc_${{ github.event.release.name }}_DragonFlyBSD-64bit.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags '' -o croc
tar -czvf croc_${{ github.event.release.name }}_FreeBSD-64bit.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags '' -o croc
tar -czvf croc_${{ github.event.release.name }}_FreeBSD-ARM64.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=netbsd GOARCH=386 go build -ldflags '' -o croc
tar -czvf croc_${{ github.event.release.name }}_NetBSD-32bit.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=netbsd GOARCH=amd64 go build -ldflags '' -o croc
tar -czvf croc_${{ github.event.release.name }}_NetBSD-64bit.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=netbsd GOARCH=arm64 go build -ldflags '' -o croc
tar -czvf croc_${{ github.event.release.name }}_NetBSD-ARM64.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 go build -ldflags '' -o croc
tar -czvf croc_${{ github.event.release.name }}_OpenBSD-64bit.tar.gz croc LICENSE
CGO_ENABLED=0 GOOS=openbsd GOARCH=arm64 go build -ldflags '' -o croc
tar -czvf croc_${{ github.event.release.name }}_OpenBSD-ARM64.tar.gz croc LICENSE
- name: Create checksums.txt
run: |
touch croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_src.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Windows-64bit.zip >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Windows-32bit.zip >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Windows-ARM.zip >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Windows-ARM64.zip >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Windows7-64bit.zip >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Windows7-32bit.zip >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Linux-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Linux-32bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Linux-ARM.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_Linux-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_macOS-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_macOS-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_DragonFlyBSD-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_FreeBSD-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_FreeBSD-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_NetBSD-32bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_NetBSD-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_NetBSD-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_OpenBSD-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
sha256sum croc_${{ github.event.release.name }}_OpenBSD-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
- name: Release
uses: softprops/action-gh-release@v2
with:
files: |
croc_${{ github.event.release.name }}_checksums.txt
croc_${{ github.event.release.name }}_src.tar.gz
croc_${{ github.event.release.name }}_Windows-64bit.zip
croc_${{ github.event.release.name }}_Windows-32bit.zip
croc_${{ github.event.release.name }}_Windows-ARM.zip
croc_${{ github.event.release.name }}_Windows-ARM64.zip
croc_${{ github.event.release.name }}_Windows7-64bit.zip
croc_${{ github.event.release.name }}_Windows7-32bit.zip
croc_${{ github.event.release.name }}_Linux-64bit.tar.gz
croc_${{ github.event.release.name }}_Linux-32bit.tar.gz
croc_${{ github.event.release.name }}_Linux-ARM.tar.gz
croc_${{ github.event.release.name }}_Linux-ARM64.tar.gz
croc_${{ github.event.release.name }}_macOS-64bit.tar.gz
croc_${{ github.event.release.name }}_macOS-ARM64.tar.gz
croc_${{ github.event.release.name }}_DragonFlyBSD-64bit.tar.gz
croc_${{ github.event.release.name }}_FreeBSD-64bit.tar.gz
croc_${{ github.event.release.name }}_FreeBSD-ARM64.tar.gz
croc_${{ github.event.release.name }}_NetBSD-32bit.tar.gz
croc_${{ github.event.release.name }}_NetBSD-64bit.tar.gz
croc_${{ github.event.release.name }}_NetBSD-ARM64.tar.gz
croc_${{ github.event.release.name }}_OpenBSD-64bit.tar.gz
croc_${{ github.event.release.name }}_OpenBSD-ARM64.tar.gz

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

@ -0,0 +1,27 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/actions/stale
name: Mark stale issues and pull requests
on:
schedule:
- cron: '19 12 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Stale issue message'
stale-pr-message: 'Stale pull request message'
stale-issue-label: 'no-issue-activity'
stale-pr-label: 'no-pr-activity'

14
.github/workflows/winget.yml vendored Normal file
View File

@ -0,0 +1,14 @@
name: Publish to Winget
on:
release:
types: [released]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: vedantmgoyal2009/winget-releaser@v2
with:
identifier: schollz.croc
installers-regex: '_Windows-\w+\.zip$'
token: ${{ secrets.WINGET_TOKEN }}

14
.gitignore vendored
View File

@ -1,3 +1,13 @@
# IDEs
.idea/
# Binaries
/croc
/croc.exe
zsh_autocomplete
bash_autocomplete
dist
bin
croc-stdin*
.idea/
.vscode/
src/utils/bigfile.test
test1/

100
.goreleaser.yml Normal file
View File

@ -0,0 +1,100 @@
project_name: croc
build:
main: main.go
binary: croc
ldflags: -s -w -X main.Version="v{{.Version}}-{{.Date}}"
env:
- CGO_ENABLED=0
goos:
- darwin
- linux
- windows
- freebsd
- netbsd
- openbsd
- dragonfly
goarch:
- amd64
- 386
- arm
- arm64
ignore:
- goos: darwin
goarch: 386
- goos: freebsd
goarch: arm
goarm:
- 7
nfpms:
-
formats:
- deb
vendor: "schollz.com"
homepage: "https://schollz.com/software/croc/"
maintainer: "Zack Scholl <zack.scholl@gmail.com>"
description: "A simple, secure, and fast way to transfer data."
license: "MIT"
file_name_template: "{{.ProjectName}}_{{.Version}}_{{.Os}}-{{.Arch}}"
replacements:
amd64: 64bit
386: 32bit
arm: ARM
arm64: ARM64
darwin: macOS
linux: Linux
windows: Windows
openbsd: OpenBSD
netbsd: NetBSD
freebsd: FreeBSD
dragonfly: DragonFlyBSD
archives:
-
format: tar.gz
format_overrides:
- goos: windows
format: zip
name_template: "{{.ProjectName}}_{{.Version}}_{{.Os}}-{{.Arch}}"
replacements:
amd64: 64bit
386: 32bit
arm: ARM
arm64: ARM64
darwin: macOS
linux: Linux
windows: Windows
openbsd: OpenBSD
netbsd: NetBSD
freebsd: FreeBSD
dragonfly: DragonFlyBSD
files:
- README.md
- LICENSE
- zsh_autocomplete
- bash_autocomplete
brews:
-
tap:
owner: schollz
name: homebrew-tap
folder: Formula
description: "croc is a tool that allows any two computers to simply and securely transfer files and folders."
homepage: "https://schollz.com/software/croc/"
install: |
bin.install "croc"
test: |
system "#{bin}/croc --version"
scoop:
bucket:
owner: schollz
name: scoop-bucket
homepage: "https://schollz.com/software/croc/"
description: "croc is a tool that allows any two computers to simply and securely transfer files and folders."
license: MIT
announce:
twitter:
# Wether its enabled or not.
# Defaults to false.
enabled: false

View File

@ -1,16 +1,23 @@
language: go
go:
- 1.9
- tip
env:
- "PATH=/home/travis/gopath/bin:$PATH"
before_install:
- go get github.com/gosuri/uiprogress
- go get github.com/schollz/mnemonicode
- go get github.com/pkg/errors
- go get github.com/sirupsen/logrus
- go get github.com/verybluebot/tarinator-go
install: true
script:
- go test -v
- env GO111MODULE=on go build -v
- 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/v10/src/croc
- 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/v10/src/tcp
- 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/v10/src/comm
branches:
except:
- dev
- win

View File

@ -1,46 +0,0 @@
# Contributor Covenant Code of Conduct
## 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, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment 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
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/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
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our 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.
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.
## 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.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at zack.scholl@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems 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.
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.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

16
Dockerfile Normal file
View File

@ -0,0 +1,16 @@
FROM golang:1.22-alpine as builder
RUN apk add --no-cache git gcc musl-dev
WORKDIR /go/croc
COPY . .
RUN go build -v -ldflags="-s -w"
FROM alpine:latest
EXPOSE 9009
EXPOSE 9010
EXPOSE 9011
EXPOSE 9012
EXPOSE 9013
COPY --from=builder /go/croc/croc /go/croc/croc-entrypoint.sh /
USER nobody
ENTRYPOINT ["/croc-entrypoint.sh"]
CMD ["relay"]

69
Gopkg.lock generated
View File

@ -1,69 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
branch = "master"
name = "github.com/dustin/go-humanize"
packages = ["."]
revision = "77ed807830b4df581417e7f89eb81d4872832b72"
[[projects]]
branch = "master"
name = "github.com/mars9/crypt"
packages = ["."]
revision = "65899cf653ff022fe5c7fe504b439feed9e7e0fc"
[[projects]]
name = "github.com/pkg/errors"
packages = ["."]
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
branch = "master"
name = "github.com/schollz/mnemonicode"
packages = ["."]
revision = "15c9654387fad6d257aa28f9be57b9f124101955"
[[projects]]
name = "github.com/schollz/progressbar"
packages = ["."]
revision = "b8e001516e13bd132ed253bf1b175dbfb5cdf308"
version = "v0.2.0"
[[projects]]
name = "github.com/sirupsen/logrus"
packages = ["."]
revision = "f006c2ac4710855cf0f916dd6b77acf6b048dc6e"
version = "v1.0.3"
[[projects]]
branch = "master"
name = "github.com/verybluebot/tarinator-go"
packages = ["."]
revision = "f75724675c91d0c731b69c81e0985de07663f007"
[[projects]]
branch = "master"
name = "golang.org/x/crypto"
packages = ["pbkdf2","scrypt","ssh/terminal"]
revision = "2509b142fb2b797aa7587dad548f113b2c0f20ce"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix","windows"]
revision = "0649f9fe46d917da5591af4d4784b6badd31d7e5"
[[projects]]
branch = "master"
name = "golang.org/x/text"
packages = ["transform"]
revision = "6eab0e8f74e86c598ec3b6fad4888e0c11482d48"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "bdbf624014ff879def63602194ddf9c775d9d8461e0b2e687314dc8b855ffc50"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -1,38 +0,0 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
branch = "master"
name = "github.com/gosuri/uiprogress"
[[constraint]]
name = "github.com/pkg/errors"
version = "0.8.0"
[[constraint]]
branch = "master"
name = "github.com/schollz/mnemonicode"
[[constraint]]
name = "github.com/sirupsen/logrus"
version = "1.0.3"

View File

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

366
README.md
View File

@ -1,116 +1,250 @@
<p align="center">
<img
src="https://user-images.githubusercontent.com/6550035/31846899-2b8a7034-b5cf-11e7-9643-afe552226c59.png"
width="100%" border="0" alt="croc">
<br>
<a href="https://travis-ci.org/schollz/croc"><img src="https://travis-ci.org/schollz/croc.svg?branch=master" alt="Build Status"></a>
<a href="https://github.com/schollz/croc/releases/latest"><img src="https://img.shields.io/badge/version-0.2.0-green.svg?style=flat-square" alt="Version"></a>
<a href="https://gitter.im/schollz/croc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge"><img src="https://img.shields.io/badge/chat-on%20gitter-green.svg?style=flat-square" alt="Gitter"></a>
<a href="https://goreportcard.com/report/github.com/schollz/croc"><img src="https://goreportcard.com/badge/github.com/schollz/croc" alt="Go Report Card"></a>
<a href="https://godoc.org/github.com/schollz/croc"><img src="https://godoc.org/github.com/schollz/croc?status.svg" alt="GoDoc"></a>
</p>
<p align="center">Secure transfer of stuff from one side of the internet to the other.</p>
This is more or less (but mostly *less*) a Golang port of [@warner's](https://github.com/warner) [*magic-wormhole*](https://github.com/warner/magic-wormhole) which allows you to directly transfer files and folders between computers. I decided to make this because I wanted to send my friend Jessie a file using *magic-wormhole* and when I told Jessie how to install the dependencies she made this face: :sob:. So, nominally, *croc* does the same thing (encrypted file transfer directly between computers) without dependencies so you can just double-click on your computer, even if you use Windows.
**Don't we have enough open-source peer-to-peer file-transfer utilities?**
[There](https://github.com/cowbell/sharedrop) [are](https://github.com/webtorrent/instant.io) [great](https://github.com/kern/filepizza) [tools](https://github.com/warner/magic-wormhole) [that](https://github.com/zerotier/toss) [already](https://github.com/ipfs/go-ipfs) [do](https://github.com/zerotier/toss) [this](https://github.com/nils-werner/zget). But, no we don't, because after review, [I found it was useful to make a new one](https://schollz.github.io/sending-a-file/).
# Example
_These two gifs should run in sync if you force-reload (Ctl+F5)_
**Sender:**
![send](https://user-images.githubusercontent.com/6550035/31864532-ad80c6ae-b71b-11e7-91f9-bcba8143d3cf.gif)
**Receiver:**
![receive](https://user-images.githubusercontent.com/6550035/31864531-ad6e22c4-b71b-11e7-901a-02a210057cf1.gif)
**Sender:**
```
$ croc -send croc.exe
Sending 4.4 MB file named 'croc.exe'
Code is: 4-cement-galaxy-alpha
Sending (->24.65.41.43:50843)..
0s [==========================================================] 100%
File sent.
```
**Receiver:**
```
$ croc
Enter receive code: 4-cement-galaxy-alpha
Receiving file (4.4 MB) into: croc.exe
ok? (y/n): y
Receiving (<-50.32.38.188:50843)..
0s [==========================================================] 100%
Received file written to croc.exe
```
Note, by default, you don't need any arguments for receiving! This makes it possible for you to just double click the executable to run (nice for those of us that aren't computer wizards).
# Install
[Download the latest release for your system](https://github.com/schollz/croc/releases/latest).
Or, you can [install Go](https://golang.org/dl/) and build from source with `go get github.com/schollz/croc`.
# How does it work?
*croc* is similar to [magic-wormhole](https://github.com/warner/magic-wormhole#design) in spirit and design. Like *magic-wormhole*, *croc* generates a code phrase for you to share with your friend which allows secure end-to-end transfering of files and folders through a intermediary relay that connects the TCP ports between the two computers.
In *croc*, code phrase is 16 random bits that are [menemonic encoded](http://web.archive.org/web/20101031205747/http://www.tothink.com/mnemonic/) plus a prepended integer to specify number of threads. This code phrase is hashed using sha256 and sent to a relay which maps that key to that connection. When the relay finds a matching key for both the receiver and the sender (i.e. they both have the same code phrase), then the sender transmits the encrypted metadata to the receiver through the relay. Then the receiver decrypts and reviews the metadata (file name, size), and chooses whether to consent to the transfer.
After the receiver consents to the transfer, the sender transmits encrypted data through the relay. The relay setups up [Go channels](https://golang.org/doc/effective_go.html?h=chan#channels) for each connection which pipes all the data incoming from that sender's connection out to the receiver's connection. After the transmission the channels are destroyed and all the connection and meta data information is wiped from the relay server. The encrypted file data never is stored on the relay.
**Encryption**
Encryption uses PBKDF2 (see [RFC2898](http://www.ietf.org/rfc/rfc2898.txt)) where the code phrase shared between the sender and receiver is used as the passphrase. For each of the two encrypted data blocks (metadata stored on relay server, and file data transmitted), a random 8-byte salt is used and a IV is generated according to [NIST Recommendation for Block ciphers, Section 8.2](http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf).
**Decryption**
On the receiver's computer, each piece of received encrypted data is written to a separate file. These files are concatenated and then decrypted. The hash of the decrypted file is then checked against the hash transmitted from the sender (part of the meta data block).
## Run your own relay
*croc* relies on a TCP relay to staple the parallel incoming and outgoing connections. The relay temporarily stores connection information and the encrypted meta information. The default uses a public relay at, `cowyo.com`, which has no guarantees except that I guarantee to turn if off as soon as it gets abused ([click here to check the current status of the public relay](https://stats.uptimerobot.com/lOwJYIgRm)).
I recommend you run your own relay, it is very easy. On your server, `your-server.com`, just run
```
$ croc -relay
```
Now, when you use *croc* to send and receive you should add `-server your-server.com` to use your relay server.
_Note:_ If you are behind a firewall, make sure to open up TCP ports 27001-27009.
# Contribute
I am awed by all the [great contributions](#acknowledgements) made! If you feel like contributing, in any way, by all means you can send an Issue, a PR, ask a question, or tweet me ([@yakczar](http://ctt.ec/Rq054)).
# License
MIT
# Acknowledgements
Thanks...
- ...[@warner](https://github.com/warner) for the [idea](https://github.com/warner/magic-wormhole).
- ...[@tscholl2](https://github.com/tscholl2) for the [encryption gists](https://gist.github.com/tscholl2/dc7dc15dc132ea70a98e8542fefffa28).
- ...[@skorokithakis](https://github.com/skorokithakis) for [code on proxying two connections](https://www.stavros.io/posts/proxying-two-connections-go/).
- ...for making pull requests [@Girbons](https://github.com/Girbons), [@techtide](https://github.com/techtide), [@heymatthew](https://github.com/heymatthew), [@Lunsford94](https://github.com/Lunsford94), [@lummie](https://github.com/lummie), [@jesuiscamille](https://github.com/jesuiscamille), [@threefjord](https://github.com/threefjord), [@marcossegovia](https://github.com/marcossegovia), [@csleong98](https://github.com/csleong98), [@afotescu](https://github.com/afotescu), [@callmefever](https://github.com/callmefever), [@El-JojA](https://github.com/El-JojA), [@anatolyyyyyy](https://github.com/anatolyyyyyy)!
<p align="center">
<img
src="https://user-images.githubusercontent.com/6550035/46709024-9b23ad00-cbf6-11e8-9fb2-ca8b20b7dbec.jpg"
width="408px" border="0" alt="croc">
<br>
<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://github.com/schollz/croc/actions/workflows/ci.yml"><img
src="https://github.com/schollz/croc/actions/workflows/ci.yml/badge.svg" alt="Build
Status"></a>
<p align="center">This project is supported by <a href="https://github.com/sponsors/schollz">Github sponsors</a>.</p>
`croc` is a tool that allows any two computers to simply and securely transfer files and folders. AFAIK, *croc* is the only CLI file-transfer tool that does **all** of the following:
- allows **any two computers** to transfer data (using a relay)
- provides **end-to-end encryption** (using PAKE)
- enables easy **cross-platform** transfers (Windows, Linux, Mac)
- allows **multiple file** transfers
- allows **resuming transfers** that are interrupted
- local server or port-forwarding **not needed**
- **ipv6-first** with ipv4 fallback
- can **use proxy**, like tor
For more information about `croc`, see [my blog post](https://schollz.com/software/croc6) or read a [recent interview I did](https://console.substack.com/p/console-91).
![Example](src/install/customization.gif)
## Install
Download [the latest release for your system](https://github.com/schollz/croc/releases/latest), or install a release from the command-line:
```
curl https://getcroc.schollz.com | bash
```
On macOS you can install the latest release with [Homebrew](https://brew.sh/):
```
brew install croc
```
On macOS you can also install the latest release with [MacPorts](https://macports.org/):
```
sudo port selfupdate
sudo port install croc
```
On Windows you can install the latest release with [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org), or [Winget](https://learn.microsoft.com/en-us/windows/package-manager/):
```
scoop install croc
```
```
choco install croc
```
```
winget install schollz.croc
```
On Unix you can install the latest release with [Nix](https://nixos.org/nix):
```
nix-env -i croc
```
On Alpine Linux you have to install dependencies first:
```
apk add bash coreutils
wget -qO- https://getcroc.schollz.com | bash
```
On Arch Linux you can install the latest release with `pacman`:
```
pacman -S croc
```
On Fedora you can install with `dnf`:
```
dnf install croc
```
On Gentoo you can install with `portage`:
```
emerge net-misc/croc
```
On Termux you can install with `pkg`:
```
pkg install croc
```
On FreeBSD you can install with `pkg`:
```
pkg install croc
```
Or, you can [install Go](https://golang.org/dl/) and build from source (requires Go 1.17+):
```
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/).
## Usage
To send a file, simply do:
```
$ croc send [file(s)-or-folder]
Sending 'file-or-folder' (X MB)
Code is: code-phrase
```
Then to receive the file (or folder) on another computer, you can just do
```
croc code-phrase
```
The code phrase is used to establish password-authenticated key agreement ([PAKE](https://en.wikipedia.org/wiki/Password-authenticated_key_agreement)) which generates a secret key for the sender and recipient to use for end-to-end encryption.
There are a number of configurable options (see `--help`). A set of options (like custom relay, ports, and code phrase) can be set using `--remember`.
### Custom code phrase
You can send with your own code phrase (must be more than 6 characters).
```
croc send --code [code-phrase] [file(s)-or-folder]
```
### Allow overwriting without prompt
By default, croc will prompt whether to overwrite a file. You can automatically overwrite files by using the `--overwrite` flag (recipient only). For example, receive a file to automatically overwrite:
```
croc --yes --overwrite <code>
```
### Use pipes - stdin and stdout
You can pipe to `croc`:
```
cat [filename] | croc send
```
In this case `croc` will automatically use the stdin data and send and assign a filename like "croc-stdin-123456789". To receive to `stdout` at you can always just use the `--yes` will automatically approve the transfer and pipe it out to `stdout`.
```
croc --yes [code-phrase] > out
```
All of the other text printed to the console is going to `stderr` so it will not interfere with the message going to `stdout`.
### Send text
Sometimes you want to send URLs or short text. In addition to piping, you can easily send text with `croc`:
```
croc send --text "hello world"
```
This will automatically tell the receiver to use `stdout` when they receive the text so it will be displayed.
### Use a proxy
You can use a proxy as your connection to the relay by adding a proxy address with `--socks5`. For example, you can send via a tor relay:
```
croc --socks5 "127.0.0.1:9050" send SOMEFILE
```
### Change encryption curve
You can choose from several different elliptic curves to use for encryption by using the `--curve` flag. Only the recipient can choose the curve. For example, receive a file using the P-521 curve:
```
croc --curve p521 <codephrase>
```
Available curves are P-256, P-348, P-521 and SIEC. P-256 is the default curve.
### Change hash algorithm
You can choose from several different hash algorithms. The default is the `xxhash` algorithm which is fast and thorough. If you want to optimize for speed you can use the `imohash` algorithm which is even faster, but since it samples files (versus reading the whole file) it can mistakenly determine that a file is the same on the two computers transferring - though this is only a problem if you are syncing files versus sending a new file to a computer.
```
croc send --hash imohash SOMEFILE
```
### Self-host relay
The relay is needed to staple the parallel incoming and outgoing connections. By default, `croc` uses a public relay but you can also run your own relay:
```
croc relay
```
By default it uses TCP ports 9009-9013. Make sure to open those up. You can customize the ports (e.g. `croc relay --ports 1111,1112`), but you must have a minimum of **2** ports for the relay. The first port is for communication and the subsequent ports are used for the multiplexed data transfer.
You can send files using your relay by entering `--relay` to change the relay that you are using if you want to custom host your own.
```
croc --relay "myrelay.example.com:9009" send [filename]
```
Note, when sending, you only need to include the first port (the communication port). The subsequent ports for data transfer will be transmitted back to the user from the relay.
#### Self-host relay (docker)
If it's easier you can also run a relay with Docker:
```
docker run -d -p 9009-9013:9009-9013 -e CROC_PASS='YOURPASSWORD' schollz/croc
```
Be sure to include the password for the relay otherwise any requests will be rejected.
```
croc --pass YOURPASSWORD --relay "myreal.example.com:9009" send [filename]
```
Note: when including `--pass YOURPASSWORD` you can instead pass a file with the password, e.g. `--pass FILEWITHPASSWORD`.
## License
MIT
## Acknowledgements
`croc` has gone through many iterations, and I am awed by all the great contributions! If you feel like contributing, in any way, by all means you can send an Issue, a PR, or ask a question.
Thanks [@warner](https://github.com/warner) for the [idea](https://github.com/warner/magic-wormhole), [@tscholl2](https://github.com/tscholl2) for the [encryption gists](https://gist.github.com/tscholl2/dc7dc15dc132ea70a98e8542fefffa28), [@skorokithakis](https://github.com/skorokithakis) for [code on proxying two connections](https://www.stavros.io/posts/proxying-two-connections-go/). Finally thanks for making pull requests [@maximbaz](https://github.com/maximbaz), [@meyermarcel](https://github.com/meyermarcel), [@Girbons](https://github.com/Girbons), [@techtide](https://github.com/techtide), [@heymatthew](https://github.com/heymatthew), [@Lunsford94](https://github.com/Lunsford94), [@lummie](https://github.com/lummie), [@jesuiscamille](https://github.com/jesuiscamille), [@threefjord](https://github.com/threefjord), [@marcossegovia](https://github.com/marcossegovia), [@csleong98](https://github.com/csleong98), [@afotescu](https://github.com/afotescu), [@callmefever](https://github.com/callmefever), [@El-JojA](https://github.com/El-JojA), [@anatolyyyyyy](https://github.com/anatolyyyyyy), [@goggle](https://github.com/goggle), [@smileboywtu](https://github.com/smileboywtu), [@nicolashardy](https://github.com/nicolashardy), [@fbartels](https://github.com/fbartels), [@rkuprov](https://github.com/rkuprov), [@hreese](https://github.com/hreese), [@xenrox](https://github.com/xenrox) and [Ipar](https://github.com/lpar)!

View File

@ -1,609 +0,0 @@
package main
import (
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net"
"os"
"path"
"strconv"
"strings"
"sync"
"time"
humanize "github.com/dustin/go-humanize"
"github.com/schollz/progressbar"
"github.com/verybluebot/tarinator-go"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
type Connection struct {
Server string
File FileMetaData
NumberOfConnections int
Code string
HashedCode string
Path string
IsSender bool
AskPath bool
Debug bool
DontEncrypt bool
Wait bool
bar *progressbar.ProgressBar
rate int
}
type FileMetaData struct {
Name string
Size int
Hash string
Path string
IsDir bool
IsEncrypted bool
}
const (
crocReceiveDir = "croc_received"
tmpTarGzFileName = "to_send.tmp.tar.gz"
)
func NewConnection(flags *Flags) (*Connection, error) {
c := new(Connection)
c.Debug = flags.Debug
c.DontEncrypt = flags.DontEncrypt
c.Wait = flags.Wait
c.Server = flags.Server
c.Code = flags.Code
c.NumberOfConnections = flags.NumberOfConnections
c.rate = flags.Rate
if len(flags.File) > 0 {
// check wether the file is a dir
info, err := os.Stat(flags.File)
if err != nil {
return c, err
}
if info.Mode().IsDir() { // if our file is a dir
fmt.Println("compressing directory...")
// we "tarify" the file
err = tarinator.Tarinate([]string{flags.File}, path.Base(flags.File)+".tar")
if err != nil {
return c, err
}
// now, we change the target file name to match the new archive created
flags.File = path.Base(flags.File) + ".tar"
// we set the value IsDir to true
c.File.IsDir = true
}
c.File.Name = path.Base(flags.File)
c.File.Path = path.Dir(flags.File)
c.IsSender = true
} else {
c.IsSender = false
c.AskPath = flags.PathSpec
c.Path = flags.Path
}
log.SetFormatter(&log.TextFormatter{})
if c.Debug {
log.SetLevel(log.DebugLevel)
} else {
log.SetLevel(log.WarnLevel)
}
return c, nil
}
func (c *Connection) Run() error {
forceSingleThreaded := false
if c.IsSender {
fsize, err := FileSize(path.Join(c.File.Path, c.File.Name))
if err != nil {
return err
}
if fsize < MAX_NUMBER_THREADS*BUFFERSIZE {
forceSingleThreaded = true
log.Debug("forcing single thread")
}
}
log.Debug("checking code validity")
for {
// check code
goodCode := true
m := strings.Split(c.Code, "-")
log.Debug(m)
numThreads, errParse := strconv.Atoi(m[0])
if len(m) < 2 {
goodCode = false
log.Debug("code too short")
} else if numThreads > MAX_NUMBER_THREADS || numThreads < 1 || (forceSingleThreaded && numThreads != 1) {
c.NumberOfConnections = MAX_NUMBER_THREADS
goodCode = false
log.Debug("incorrect number of threads")
} else if errParse != nil {
goodCode = false
log.Debug("problem parsing threads")
}
log.Debug(m)
log.Debug(goodCode)
if !goodCode {
if c.IsSender {
if forceSingleThreaded {
c.NumberOfConnections = 1
}
c.Code = strconv.Itoa(c.NumberOfConnections) + "-" + GetRandomName()
} else {
if len(c.Code) != 0 {
fmt.Println("Code must begin with number of threads (e.g. 3-some-code)")
}
c.Code = getInput("Enter receive code: ")
}
} else {
break
}
}
// assign number of connections
c.NumberOfConnections, _ = strconv.Atoi(strings.Split(c.Code, "-")[0])
if c.IsSender {
if c.DontEncrypt {
// don't encrypt
CopyFile(path.Join(c.File.Path, c.File.Name), c.File.Name+".enc")
c.File.IsEncrypted = false
} else {
// encrypt
log.Debug("encrypting...")
if err := EncryptFile(path.Join(c.File.Path, c.File.Name), c.File.Name+".enc", c.Code); err != nil {
return err
}
c.File.IsEncrypted = true
}
// split file into pieces to send
if err := SplitFile(c.File.Name+".enc", c.NumberOfConnections); err != nil {
return err
}
// get file hash
var err error
c.File.Hash, err = HashFile(path.Join(c.File.Path, c.File.Name))
if err != nil {
return err
}
// get file size
c.File.Size, err = FileSize(c.File.Name + ".enc")
if err != nil {
return err
}
// remove the file now since we still have pieces
if err := os.Remove(c.File.Name + ".enc"); err != nil {
return err
}
// remove compressed archive
if c.File.IsDir {
log.Debug("removing archive: " + c.File.Name)
if err := os.Remove(c.File.Name); err != nil {
return err
}
}
if c.File.IsDir {
fmt.Printf("Sending %s folder named '%s'\n", humanize.Bytes(uint64(c.File.Size)), c.File.Name[:len(c.File.Name)-4])
} else {
fmt.Printf("Sending %s file named '%s'\n", humanize.Bytes(uint64(c.File.Size)), c.File.Name)
}
fmt.Printf("Code is: %s\n", c.Code)
}
return c.runClient()
}
// runClient spawns threads for parallel uplink/downlink via TCP
func (c *Connection) runClient() error {
logger := log.WithFields(log.Fields{
"code": c.Code,
"sender?": c.IsSender,
})
startTime := time.Now()
c.HashedCode = Hash(c.Code)
var wg sync.WaitGroup
wg.Add(c.NumberOfConnections)
if !c.Debug {
c.bar = progressbar.New(c.File.Size)
}
type responsesStruct struct {
gotTimeout bool
gotOK bool
gotResponse bool
gotConnectionInUse bool
notPresent bool
sync.RWMutex
}
responses := new(responsesStruct)
for id := 0; id < c.NumberOfConnections; id++ {
go func(id int) {
defer wg.Done()
port := strconv.Itoa(27001 + id)
connection, err := net.Dial("tcp", c.Server+":"+port)
if err != nil {
if c.Server == "cowyo.com" {
fmt.Println("\nCheck http://bit.ly/croc-relay to see if the public server is down or contact the webmaster: @yakczar")
} else {
fmt.Printf("\nCould not connect to relay %s\n", c.Server)
}
os.Exit(1)
}
defer connection.Close()
message := receiveMessage(connection)
logger.Debugf("relay says: %s", message)
if c.IsSender {
logger.Debugf("telling relay: %s", "s."+c.Code)
metaData, err := json.Marshal(c.File)
if err != nil {
log.Error(err)
}
encryptedMetaData, salt, iv := Encrypt(metaData, c.Code)
sendMessage("s."+c.HashedCode+"."+hex.EncodeToString(encryptedMetaData)+"-"+salt+"-"+iv, connection)
} else {
logger.Debugf("telling relay: %s", "r."+c.Code)
if c.Wait {
// tell server to wait for sender
sendMessage("r."+c.HashedCode+".0.0.0", connection)
} else {
// tell server to cancel if sender doesn't exist
sendMessage("c."+c.HashedCode+".0.0.0", connection)
}
}
if c.IsSender { // this is a sender
logger.Debug("waiting for ok from relay")
message = receiveMessage(connection)
if message == "timeout" {
responses.Lock()
responses.gotTimeout = true
responses.Unlock()
fmt.Println("You've just exceeded limit waiting time.")
return
}
if message == "no" {
if id == 0 {
fmt.Println("The specifed code is already in use by a sender.")
}
responses.Lock()
responses.gotConnectionInUse = true
responses.Unlock()
} else {
logger.Debug("got ok from relay")
if id == 0 {
fmt.Printf("\nSending (->%s)..\n", message)
}
// wait for pipe to be made
time.Sleep(100 * time.Millisecond)
// Write data from file
logger.Debug("send file")
startTime = time.Now()
c.bar.Reset()
if err := c.sendFile(id, connection); err != nil {
log.Error(err)
}
}
} else { // this is a receiver
logger.Debug("waiting for meta data from sender")
message = receiveMessage(connection)
if message == "no" {
if id == 0 {
fmt.Println("The specifed code is already in use by a sender.")
}
responses.Lock()
responses.gotConnectionInUse = true
responses.Unlock()
} else {
m := strings.Split(message, "-")
encryptedData, salt, iv, sendersAddress := m[0], m[1], m[2], m[3]
if sendersAddress == "0.0.0.0" {
responses.Lock()
responses.notPresent = true
responses.Unlock()
time.Sleep(1 * time.Second)
return
}
// have the main thread ask for the okay
if id == 0 {
encryptedBytes, err := hex.DecodeString(encryptedData)
if err != nil {
log.Error(err)
return
}
decryptedBytes, _ := Decrypt(encryptedBytes, c.Code, salt, iv, c.DontEncrypt)
err = json.Unmarshal(decryptedBytes, &c.File)
if err != nil {
log.Error(err)
return
}
log.Debugf("meta data received: %v", c.File)
fType := "file"
fName := path.Join(c.Path, c.File.Name)
if c.File.IsDir {
fType = "folder"
fName = fName[:len(fName)-4]
}
if _, err := os.Stat(path.Join(c.Path, c.File.Name)); os.IsNotExist(err) {
fmt.Printf("Receiving %s (%s) into: %s\n", fType, humanize.Bytes(uint64(c.File.Size)), fName)
} else {
fmt.Printf("Overwriting %s %s (%s)\n", fType, fName, humanize.Bytes(uint64(c.File.Size)))
}
var sentFileNames []string
if c.AskPath {
getPath := getInput("path: ")
if len(getPath) > 0 {
c.Path = path.Clean(getPath)
}
}
if fileAlreadyExists(sentFileNames, c.File.Name) {
fmt.Printf("Will not overwrite file!")
os.Exit(1)
}
getOK := getInput("ok? (y/n): ")
if getOK == "y" {
responses.Lock()
responses.gotOK = true
responses.Unlock()
sentFileNames = append(sentFileNames, c.File.Name)
}
responses.Lock()
responses.gotResponse = true
responses.Unlock()
}
// wait for the main thread to get the okay
for limit := 0; limit < 1000; limit++ {
responses.Lock()
gotResponse := responses.gotResponse
responses.Unlock()
if gotResponse {
break
}
time.Sleep(10 * time.Millisecond)
}
responses.RLock()
gotOK := responses.gotOK
responses.RUnlock()
if !gotOK {
sendMessage("not ok", connection)
} else {
sendMessage("ok", connection)
logger.Debug("receive file")
if id == 0 {
fmt.Printf("\n\nReceiving (<-%s)..\n", sendersAddress)
}
startTime = time.Now()
c.bar.SetMax(c.File.Size)
c.bar.Reset()
if err := c.receiveFile(id, connection); err != nil {
log.Error(errors.Wrap(err, "Problem receiving the file: "))
}
}
}
}
}(id)
}
wg.Wait()
responses.Lock()
defer responses.Unlock()
if responses.gotConnectionInUse {
return nil // connection was in use, just quit cleanly
}
if c.IsSender {
if responses.gotTimeout {
fmt.Println("Timeout waiting for receiver")
return nil
}
fmt.Print("\nFile sent")
} else { // Is a Receiver
if responses.notPresent {
fmt.Println("Sender is not ready. Use -wait to wait until sender connects.")
return nil
}
if !responses.gotOK {
return errors.New("Transfer interrupted")
}
if err := c.catFile(); err != nil {
return err
}
log.Debugf("Code: [%s]", c.Code)
if c.DontEncrypt {
if err := CopyFile(path.Join(c.Path, c.File.Name+".enc"), path.Join(c.Path, c.File.Name)); err != nil {
return err
}
} else {
if c.File.IsEncrypted {
if err := DecryptFile(path.Join(c.Path, c.File.Name+".enc"), path.Join(c.Path, c.File.Name), c.Code); err != nil {
return errors.Wrap(err, "Problem decrypting file")
}
} else {
if err := CopyFile(path.Join(c.Path, c.File.Name+".enc"), path.Join(c.Path, c.File.Name)); err != nil {
return errors.Wrap(err, "Problem copying file")
}
}
}
if !c.Debug {
os.Remove(path.Join(c.Path, c.File.Name+".enc"))
}
fileHash, err := HashFile(path.Join(c.Path, c.File.Name))
if err != nil {
log.Error(err)
}
log.Debugf("\n\n\ndownloaded hash: [%s]", fileHash)
log.Debugf("\n\n\nrelayed hash: [%s]", c.File.Hash)
if c.File.Hash != fileHash {
return fmt.Errorf("\nUh oh! %s is corrupted! Sorry, try again.\n", c.File.Name)
}
if c.File.IsDir { // if the file was originally a dir
fmt.Print("\ndecompressing folder")
log.Debug("untarring " + c.File.Name)
err := tarinator.UnTarinate(c.Path, path.Join(c.Path, c.File.Name))
if err != nil {
return err
}
// we remove the old tar.gz file
err = os.Remove(path.Join(c.Path, c.File.Name))
if err != nil {
return err
}
fmt.Printf("\nReceived folder written to %s", path.Join(c.Path, c.File.Name[:len(c.File.Name)-4]))
} else {
fmt.Printf("\nReceived file written to %s", path.Join(c.Path, c.File.Name))
}
}
timeSinceStart := time.Since(startTime) / time.Second
fmt.Printf(" (%s/s)\n", humanize.Bytes(uint64(float64(c.File.Size)/float64(timeSinceStart))))
return nil
}
func fileAlreadyExists(s []string, f string) bool {
for _, a := range s {
if a == f {
return true
}
}
return false
}
func (c *Connection) catFile() error {
// cat the file
files := make([]string, c.NumberOfConnections)
for id := range files {
files[id] = path.Join(c.Path, c.File.Name+".enc."+strconv.Itoa(id))
}
toRemove := !c.Debug
return CatFiles(files, path.Join(c.Path, c.File.Name+".enc"), toRemove)
}
func (c *Connection) receiveFile(id int, connection net.Conn) error {
logger := log.WithFields(log.Fields{
"function": "receiveFile #" + strconv.Itoa(id),
})
logger.Debug("waiting for chunk size from sender")
fileSizeBuffer := make([]byte, 10)
connection.Read(fileSizeBuffer)
fileDataString := strings.Trim(string(fileSizeBuffer), ":")
fileSizeInt, _ := strconv.Atoi(fileDataString)
chunkSize := int64(fileSizeInt)
logger.Debugf("chunk size: %d", chunkSize)
if chunkSize == 0 {
logger.Debug(fileSizeBuffer)
return errors.New("chunk size is empty!")
}
os.Remove(path.Join(c.Path, c.File.Name+".enc."+strconv.Itoa(id)))
log.Debug("Making " + c.File.Name + ".enc." + strconv.Itoa(id))
newFile, err := os.Create(path.Join(c.Path, c.File.Name+".enc."+strconv.Itoa(id)))
if err != nil {
panic(err)
}
defer newFile.Close()
logger.Debug("waiting for file")
var receivedBytes int64
receivedFirstBytes := false
for {
if (chunkSize - receivedBytes) < BUFFERSIZE {
logger.Debug("at the end")
io.CopyN(newFile, connection, (chunkSize - receivedBytes))
// Empty the remaining bytes that we don't need from the network buffer
if (receivedBytes+BUFFERSIZE)-chunkSize < BUFFERSIZE {
logger.Debug("empty remaining bytes from network buffer")
connection.Read(make([]byte, (receivedBytes+BUFFERSIZE)-chunkSize))
}
if !c.Debug {
c.bar.Add(int((chunkSize - receivedBytes)))
}
break
}
io.CopyN(newFile, connection, BUFFERSIZE)
receivedBytes += BUFFERSIZE
if !receivedFirstBytes {
receivedFirstBytes = true
logger.Debug("Receieved first bytes!")
}
if !c.Debug {
c.bar.Add(BUFFERSIZE)
}
}
logger.Debug("received file")
return nil
}
func (c *Connection) sendFile(id int, connection net.Conn) error {
logger := log.WithFields(log.Fields{
"function": "sendFile #" + strconv.Itoa(id),
})
defer connection.Close()
// open encrypted file chunk
logger.Debug("opening encrypted file chunk: " + c.File.Name + ".enc." + strconv.Itoa(id))
file, err := os.Open(c.File.Name + ".enc." + strconv.Itoa(id))
if err != nil {
return err
}
defer file.Close()
// determine and send the file size to client
fi, err := file.Stat()
if err != nil {
return err
}
logger.Debugf("sending chunk size: %d", fi.Size())
_, err = connection.Write([]byte(fillString(strconv.FormatInt(int64(fi.Size()), 10), 10)))
if err != nil {
return errors.Wrap(err, "Problem sending chunk data: ")
}
// rate limit the bandwidth
logger.Debug("determining rate limiting")
bufferSizeInKilobytes := BUFFERSIZE / 1024
rate := float64(c.rate) / float64(c.NumberOfConnections*bufferSizeInKilobytes)
throttle := time.NewTicker(time.Second / time.Duration(rate))
defer throttle.Stop()
// send the file
sendBuffer := make([]byte, BUFFERSIZE)
totalBytesSent := 0
for range throttle.C {
n, err := file.Read(sendBuffer)
connection.Write(sendBuffer)
totalBytesSent += n
if !c.Debug {
c.bar.Add(n)
}
if err == io.EOF {
//End of file reached, break out of for loop
logger.Debug("EOF")
break
}
}
logger.Debug("file is sent")
logger.Debug("removing piece")
if !c.Debug {
file.Close()
err = os.Remove(c.File.Name + ".enc." + strconv.Itoa(id))
}
return err
}

6
croc-entrypoint.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
set -e
if [ -n "$CROC_PASS" ]; then
set -- --pass "$CROC_PASS" "$@"
fi
exec /croc "$@"

12
croc.service Normal file
View File

@ -0,0 +1,12 @@
[Unit]
Description=croc relay
After=network.target
[Service]
Type=simple
DynamicUser=yes
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
ExecStart=/usr/bin/croc relay
[Install]
WantedBy=multi-user.target

125
crypto.go
View File

@ -1,125 +0,0 @@
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha1"
"crypto/sha256"
"encoding/binary"
"encoding/hex"
"fmt"
mathrand "math/rand"
"os"
"strings"
"time"
"github.com/mars9/crypt"
"github.com/schollz/mnemonicode"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/pbkdf2"
)
func init() {
mathrand.Seed(time.Now().UTC().UnixNano())
}
func GetRandomName() string {
result := []string{}
bs := make([]byte, 4)
binary.LittleEndian.PutUint32(bs, mathrand.Uint32())
result = mnemonicode.EncodeWordList(result, bs)
return strings.Join(result, "-")
}
func Encrypt(plaintext []byte, passphrase string, dontencrypt ...bool) (encrypted []byte, salt string, iv string) {
if len(dontencrypt) > 0 && dontencrypt[0] {
return plaintext, "salt", "iv"
}
key, saltBytes := deriveKey(passphrase, nil)
ivBytes := make([]byte, 12)
// http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
// Section 8.2
rand.Read(ivBytes)
b, _ := aes.NewCipher(key)
aesgcm, _ := cipher.NewGCM(b)
encrypted = aesgcm.Seal(nil, ivBytes, plaintext, nil)
salt = hex.EncodeToString(saltBytes)
iv = hex.EncodeToString(ivBytes)
return
}
func Decrypt(data []byte, passphrase string, salt string, iv string, dontencrypt ...bool) (plaintext []byte, err error) {
if len(dontencrypt) > 0 && dontencrypt[0] {
return data, nil
}
saltBytes, _ := hex.DecodeString(salt)
ivBytes, _ := hex.DecodeString(iv)
key, _ := deriveKey(passphrase, saltBytes)
b, _ := aes.NewCipher(key)
aesgcm, _ := cipher.NewGCM(b)
plaintext, err = aesgcm.Open(nil, ivBytes, data, nil)
return
}
func deriveKey(passphrase string, salt []byte) ([]byte, []byte) {
if salt == nil {
salt = make([]byte, 8)
// http://www.ietf.org/rfc/rfc2898.txt
// Salt.
rand.Read(salt)
}
return pbkdf2.Key([]byte(passphrase), salt, 1000, 32, sha256.New), salt
}
func Hash(data string) string {
return HashBytes([]byte(data))
}
func HashBytes(data []byte) string {
sum := sha256.Sum256(data)
return fmt.Sprintf("%x", sum)
}
func EncryptFile(inputFilename string, outputFilename string, password string) error {
return cryptFile(inputFilename, outputFilename, password, true)
}
func DecryptFile(inputFilename string, outputFilename string, password string) error {
return cryptFile(inputFilename, outputFilename, password, false)
}
func cryptFile(inputFilename string, outputFilename string, password string, encrypt bool) error {
in, err := os.Open(inputFilename)
if err != nil {
return err
}
defer in.Close()
out, err := os.Create(outputFilename)
if err != nil {
return err
}
defer func() {
if err := out.Sync(); err != nil {
log.Error(err)
}
if err := out.Close(); err != nil {
log.Error(err)
}
}()
c := &crypt.Crypter{
HashFunc: sha1.New,
HashSize: sha1.Size,
Key: crypt.NewPbkdf2Key([]byte(password), 32),
}
if encrypt {
if err := c.Encrypt(out, in); err != nil {
return err
}
} else {
if err := c.Decrypt(out, in); err != nil {
return err
}
}
return nil
}

View File

@ -1,49 +0,0 @@
package main
import (
"io/ioutil"
"os"
"testing"
)
func TestEncrypt(t *testing.T) {
key := GetRandomName()
encrypted, salt, iv := Encrypt([]byte("hello, world"), key)
decrypted, err := Decrypt(encrypted, key, salt, iv)
if err != nil {
t.Error(err)
}
if string(decrypted) != "hello, world" {
t.Error("problem decrypting")
}
_, err = Decrypt(encrypted, "wrong passphrase", salt, iv)
if err == nil {
t.Error("should not work!")
}
}
func TestEncryptFiles(t *testing.T) {
key := GetRandomName()
if err := ioutil.WriteFile("temp", []byte("hello, world!"), 0644); err != nil {
t.Error(err)
}
if err := EncryptFile("temp", "temp.enc", key); err != nil {
t.Error(err)
}
if err := DecryptFile("temp.enc", "temp.dec", key); err != nil {
t.Error(err)
}
data, err := ioutil.ReadFile("temp.dec")
if string(data) != "hello, world!" {
t.Errorf("Got something weird: " + string(data))
}
if err != nil {
t.Error(err)
}
if err := DecryptFile("temp.enc", "temp.dec", key+"wrong password"); err == nil {
t.Error("should throw error!")
}
os.Remove("temp.dec")
os.Remove("temp.enc")
os.Remove("temp")
}

42
go.mod Normal file
View File

@ -0,0 +1,42 @@
module github.com/schollz/croc/v10
go 1.20
require (
github.com/cespare/xxhash v1.1.0
github.com/chzyer/readline v1.5.1
github.com/denisbrodbeck/machineid v1.0.1
github.com/kalafut/imohash v1.0.3
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
github.com/schollz/cli/v2 v2.2.1
github.com/schollz/logger v1.2.0
github.com/schollz/mnemonicode v1.0.2-0.20190421205639-63fa713ece0d
github.com/schollz/pake/v3 v3.0.5
github.com/schollz/peerdiscovery v1.7.3
github.com/schollz/progressbar/v3 v3.14.3
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.23.0
golang.org/x/net v0.25.0
golang.org/x/time v0.5.0
)
require github.com/minio/highwayhash v1.0.2
require (
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406 // indirect
github.com/twmb/murmur3 v1.1.8 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

132
go.sum Normal file
View File

@ -0,0 +1,132 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
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/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.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/kalafut/imohash v1.0.3 h1:p9c61km8+6ZMqKRnERwdoxp/CztrdLNEbpsyGgf+A4M=
github.com/kalafut/imohash v1.0.3/go.mod h1:6cn9lU0Sj8M4eu9UaQm1kR/5y3k/ayB68yntRhGloL4=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
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/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
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/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
github.com/schollz/cli/v2 v2.2.1 h1:ou22Mj7ZPjrKz+8k2iDTWaHskEEV5NiAxGrdsCL36VU=
github.com/schollz/cli/v2 v2.2.1/go.mod h1:My6bfphRLZUhZdlFUK8scAxMWHydE7k4s2ed2Dtnn+s=
github.com/schollz/logger v1.2.0 h1:5WXfINRs3lEUTCZ7YXhj0uN+qukjizvITLm3Ca2m0Ho=
github.com/schollz/logger v1.2.0/go.mod h1:P6F4/dGMGcx8wh+kG1zrNEd4vnNpEBY/mwEMd/vn6AM=
github.com/schollz/mnemonicode v1.0.2-0.20190421205639-63fa713ece0d h1:3zCjdgCJbo9Fot3UoqZkpGiDgT6Nf+iUnOsDEJQay+c=
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/go.mod h1:OGbG6htRwSKo6V8R5tg61ufpFmZM1b/PrrSp6g2ZLLc=
github.com/schollz/peerdiscovery v1.7.3 h1:/pt1G0rZ80fSPoI/FgGC5P7MxpkRXD6u0pe6PJbYcIE=
github.com/schollz/peerdiscovery v1.7.3/go.mod h1:mVlPNJ5DWbMi52VzpXxGbqXKdFANx3qw0Jsp3EQMCrE=
github.com/schollz/progressbar/v3 v3.14.3 h1:oOuWW19ka12wxYU1XblR4n16wF/2Y1dBLMarMo6p4xU=
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/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/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tscholl2/siec v0.0.0-20210707234609-9bdfc483d499/go.mod h1:KL9+ubr1JZdaKjgAaHr+tCytEncXBa1pR6FjbTsOJnw=
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406 h1:sDWDZkwYqX0jvLWstKzFwh+pYhQNaVg65BgSkCP/f7U=
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406/go.mod h1:KL9+ubr1JZdaKjgAaHr+tCytEncXBa1pR6FjbTsOJnw=
github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
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.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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
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.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
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-20220722155255-886fb9371eb4/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-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-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
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-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.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
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.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.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.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/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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,34 +0,0 @@
# .goreleaser.yml
# Build customization
builds:
- binary: croc
goos:
- windows
- darwin
- linux
goarch:
- amd64
- arm
- 386
goarm:
- 6
ignore:
- goos: darwin
goarch: arm
- goos: windows
goarch: arm
- goos: darwin
goarch: 386
env:
- CGO_ENABLED=0
archive:
replacements:
amd64: 64bit
386: 32bit
darwin: OSX
linux_arm: raspberry_pi
format_overrides:
- goos: windows
format: zip
- goos: darwin
format: zip

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

95
main.go
View File

@ -1,78 +1,33 @@
package main
//go:generate go run src/install/updateversion.go
//go:generate git commit -am "bump $VERSION"
//go:generate git tag -af v$VERSION -m "v$VERSION"
import (
"bufio"
"flag"
"fmt"
"os"
"strings"
"log"
"github.com/schollz/croc/v10/src/cli"
)
const BUFFERSIZE = 1024
var oneGigabytePerSecond = 1000000 // expressed as kbps
type Flags struct {
Relay bool
Debug bool
Wait bool
PathSpec bool
DontEncrypt bool
Server string
File string
Path string
Code string
Rate int
NumberOfConnections int
}
var version string
func main() {
fmt.Println(`
,_
>' )
croc version ` + fmt.Sprintf("%5s", version) + ` ( ( \
|| \
/^^^^\ ||
/^^\________/0 \ ||
( ` + "`" + `~+++,,_||__,,++~^^^^^^^
...V^V^V^V^V^V^\...............................
`)
flags := new(Flags)
flag.BoolVar(&flags.Relay, "relay", false, "run as relay")
flag.BoolVar(&flags.Debug, "debug", false, "debug mode")
flag.BoolVar(&flags.Wait, "wait", false, "wait for code to be sent")
flag.BoolVar(&flags.PathSpec, "ask-save", false, "ask for path to save to")
flag.StringVar(&flags.Server, "server", "cowyo.com", "address of relay server")
flag.StringVar(&flags.File, "send", "", "file to send")
flag.StringVar(&flags.Path, "save", "", "path to save to")
flag.StringVar(&flags.Code, "code", "", "use your own code phrase")
flag.IntVar(&flags.Rate, "rate", oneGigabytePerSecond, "throttle down to speed in kbps")
flag.BoolVar(&flags.DontEncrypt, "no-encrypt", false, "turn off encryption")
flag.IntVar(&flags.NumberOfConnections, "threads", 4, "number of threads to use")
flag.Parse()
if flags.Relay {
r := NewRelay(flags)
r.Run()
} else {
c, err := NewConnection(flags)
if err != nil {
fmt.Printf("Error! Please submit the following error to https://github.com/schollz/croc/issues:\n\n'%s'\n\n", err.Error())
return
}
err = c.Run()
if err != nil {
fmt.Printf("Error! Please submit the following error to https://github.com/schollz/croc/issues:\n\n'%s'\n\n", err.Error())
}
// "github.com/pkg/profile"
// go func() {
// for {
// f, err := os.Create("croc.pprof")
// if err != nil {
// panic(err)
// }
// runtime.GC() // get up-to-date statistics
// if err := pprof.WriteHeapProfile(f); err != nil {
// panic(err)
// }
// f.Close()
// time.Sleep(3 * time.Second)
// fmt.Println("wrote profile")
// }
// }()
if err := cli.Run(); err != nil {
log.Fatalln(err)
}
}
func getInput(prompt string) string {
reader := bufio.NewReader(os.Stdin)
fmt.Print(prompt)
text, _ := reader.ReadString('\n')
return strings.TrimSpace(text)
}

318
relay.go
View File

@ -1,318 +0,0 @@
package main
import (
"net"
"strconv"
"strings"
"sync"
"time"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
)
const MAX_NUMBER_THREADS = 8
const CONNECTION_TIMEOUT = time.Hour
type connectionMap struct {
receiver map[string]net.Conn
sender map[string]net.Conn
metadata map[string]string
potentialReceivers map[string]struct{}
sync.RWMutex
}
func (c *connectionMap) IsSenderConnected(key string) (found bool) {
c.RLock()
defer c.RUnlock()
_, found = c.sender[key]
return
}
func (c *connectionMap) IsPotentialReceiverConnected(key string) (found bool) {
c.RLock()
defer c.RUnlock()
_, found = c.potentialReceivers[key]
return
}
type Relay struct {
connections connectionMap
Debug bool
NumberOfConnections int
}
func NewRelay(flags *Flags) *Relay {
r := &Relay{
Debug: flags.Debug,
NumberOfConnections: MAX_NUMBER_THREADS,
}
log.SetFormatter(&log.TextFormatter{})
if r.Debug {
log.SetLevel(log.DebugLevel)
} else {
log.SetLevel(log.WarnLevel)
}
return r
}
func (r *Relay) Run() {
r.connections = connectionMap{}
r.connections.Lock()
r.connections.receiver = make(map[string]net.Conn)
r.connections.sender = make(map[string]net.Conn)
r.connections.metadata = make(map[string]string)
r.connections.potentialReceivers = make(map[string]struct{})
r.connections.Unlock()
r.runServer()
}
func (r *Relay) runServer() {
logger := log.WithFields(log.Fields{
"function": "main",
})
logger.Debug("Initializing")
var wg sync.WaitGroup
wg.Add(r.NumberOfConnections)
for id := 0; id < r.NumberOfConnections; id++ {
go r.listenerThread(id, &wg)
}
wg.Wait()
}
func (r *Relay) listenerThread(id int, wg *sync.WaitGroup) {
logger := log.WithFields(log.Fields{
"function": "listenerThread:" + strconv.Itoa(27000+id),
})
defer wg.Done()
if err := r.listener(id); err != nil {
logger.Error(err)
}
}
func (r *Relay) listener(id int) (err error) {
port := strconv.Itoa(27001 + id)
logger := log.WithFields(log.Fields{
"function": "listener:" + port,
})
server, err := net.Listen("tcp", "0.0.0.0:"+port)
if err != nil {
return errors.Wrap(err, "Error listening on :"+port)
}
defer server.Close()
logger.Debug("waiting for connections")
//Spawn a new goroutine whenever a client connects
for {
connection, err := server.Accept()
if err != nil {
return errors.Wrap(err, "problem accepting connection")
}
logger.Debugf("Client %s connected", connection.RemoteAddr().String())
go r.clientCommuncation(id, connection)
}
}
func (r *Relay) clientCommuncation(id int, connection net.Conn) {
logger := log.WithFields(log.Fields{
"id": id,
"ip": connection.RemoteAddr().String(),
})
sendMessage("who?", connection)
m := strings.Split(receiveMessage(connection), ".")
if len(m) < 3 {
logger.Debug("exiting, not enough information")
sendMessage("not enough information", connection)
return
}
connectionType, codePhrase, metaData := m[0], m[1], m[2]
key := codePhrase + "-" + strconv.Itoa(id)
switch connectionType {
case "s": // sender connection
if r.connections.IsSenderConnected(key) {
sendMessage("no", connection)
return
}
r.connections.Lock()
r.connections.metadata[key] = metaData
r.connections.sender[key] = connection
r.connections.Unlock()
// wait for receiver
receiversAddress := ""
isTimeout := time.Duration(0)
for {
if CONNECTION_TIMEOUT <= isTimeout {
sendMessage("timeout", connection)
break
}
r.connections.RLock()
if _, ok := r.connections.receiver[key]; ok {
receiversAddress = r.connections.receiver[key].RemoteAddr().String()
logger.Debug("got receiver")
r.connections.RUnlock()
break
}
r.connections.RUnlock()
time.Sleep(100 * time.Millisecond)
isTimeout += 100 * time.Millisecond
}
logger.Debug("telling sender ok")
sendMessage(receiversAddress, connection)
logger.Debug("preparing pipe")
r.connections.Lock()
con1 := r.connections.sender[key]
con2 := r.connections.receiver[key]
r.connections.Unlock()
logger.Debug("piping connections")
Pipe(con1, con2)
logger.Debug("done piping")
r.connections.Lock()
// close connections
r.connections.sender[key].Close()
r.connections.receiver[key].Close()
// delete connctions
delete(r.connections.sender, key)
delete(r.connections.receiver, key)
delete(r.connections.metadata, key)
delete(r.connections.potentialReceivers, key)
r.connections.Unlock()
logger.Debug("deleted sender and receiver")
case "r", "c": // receiver
if r.connections.IsPotentialReceiverConnected(key) {
sendMessage("no", connection)
return
}
// add as a potential receiver
r.connections.Lock()
r.connections.potentialReceivers[key] = struct{}{}
r.connections.Unlock()
// wait for sender's metadata
sendersAddress := ""
for {
r.connections.RLock()
if _, ok := r.connections.metadata[key]; ok {
if _, ok2 := r.connections.sender[key]; ok2 {
sendersAddress = r.connections.sender[key].RemoteAddr().String()
logger.Debug("got sender meta data")
r.connections.RUnlock()
break
}
}
r.connections.RUnlock()
if connectionType == "c" {
sendMessage("0-0-0-0.0.0.0", connection)
// sender is not ready so delete connection
r.connections.Lock()
delete(r.connections.potentialReceivers, key)
r.connections.Unlock()
return
}
time.Sleep(100 * time.Millisecond)
}
// send meta data
r.connections.RLock()
sendMessage(r.connections.metadata[key]+"-"+sendersAddress, connection)
r.connections.RUnlock()
// check for receiver's consent
consent := receiveMessage(connection)
logger.Debugf("consent: %s", consent)
if consent == "ok" {
logger.Debug("got consent")
r.connections.Lock()
r.connections.receiver[key] = connection
r.connections.Unlock()
}
default:
logger.Debugf("Got unknown protocol: '%s'", connectionType)
}
}
func sendMessage(message string, connection net.Conn) {
message = fillString(message, BUFFERSIZE)
connection.Write([]byte(message))
}
func receiveMessage(connection net.Conn) string {
logger := log.WithFields(log.Fields{
"func": "receiveMessage",
"ip": connection.RemoteAddr().String(),
})
messageByte := make([]byte, BUFFERSIZE)
err := connection.SetDeadline(time.Now().Add(60 * time.Minute))
if err != nil {
logger.Warn(err)
}
_, err = connection.Read(messageByte)
if err != nil {
logger.Warn("read deadline, no response")
return ""
}
return strings.Replace(string(messageByte), ":", "", -1)
}
func fillString(retunString string, toLength int) string {
for {
lengthString := len(retunString)
if lengthString < toLength {
retunString = retunString + ":"
continue
}
break
}
return retunString
}
// chanFromConn creates a channel from a Conn object, and sends everything it
// Read()s from the socket to the channel.
func chanFromConn(conn net.Conn) chan []byte {
c := make(chan []byte)
go func() {
b := make([]byte, BUFFERSIZE)
for {
n, err := conn.Read(b)
if n > 0 {
res := make([]byte, n)
// Copy the buffer so it doesn't get changed while read by the recipient.
copy(res, b[:n])
c <- res
}
if err != nil {
c <- nil
break
}
}
}()
return c
}
// Pipe creates a full-duplex pipe between the two sockets and transfers data from one to the other.
func Pipe(conn1 net.Conn, conn2 net.Conn) {
chan1 := chanFromConn(conn1)
chan2 := chanFromConn(conn2)
for {
select {
case b1 := <-chan1:
if b1 == nil {
return
}
conn2.Write(b1)
case b2 := <-chan2:
if b2 == nil {
return
}
conn1.Write(b2)
}
}
}

682
src/cli/cli.go Normal file
View File

@ -0,0 +1,682 @@
package cli
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
"github.com/chzyer/readline"
"github.com/schollz/cli/v2"
"github.com/schollz/croc/v10/src/comm"
"github.com/schollz/croc/v10/src/croc"
"github.com/schollz/croc/v10/src/models"
"github.com/schollz/croc/v10/src/tcp"
"github.com/schollz/croc/v10/src/utils"
log "github.com/schollz/logger"
"github.com/schollz/mnemonicode"
"github.com/schollz/pake/v3"
)
// Version specifies the version
var Version string
// Run will run the command line program
func Run() (err error) {
// use all of the processors
runtime.GOMAXPROCS(runtime.NumCPU())
app := cli.NewApp()
app.Name = "croc"
if Version == "" {
Version = "v10.0.7"
}
app.Version = Version
app.Compiled = time.Now()
app.Usage = "easily and securely transfer stuff from one computer to another"
app.UsageText = `Send a file:
croc send file.txt
-git to respect your .gitignore
Send multiple files:
croc send file1.txt file2.txt file3.txt
or
croc send *.jpg
Send everything in a folder:
croc send example-folder-name
Send a file with a custom code:
croc send --code secret-code file.txt
Receive a file using code:
croc secret-code`
app.Commands = []*cli.Command{
{
Name: "send",
Usage: "send file(s), or folder (see options with croc send -h)",
Description: "send file(s), or folder, over the relay",
ArgsUsage: "[filename(s) or folder]",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "zip", Usage: "zip folder before sending"},
&cli.StringFlag{Name: "code", Aliases: []string{"c"}, Usage: "codephrase used to connect to relay"},
&cli.StringFlag{Name: "hash", Value: "xxhash", Usage: "hash algorithm (xxhash, imohash, md5)"},
&cli.StringFlag{Name: "text", Aliases: []string{"t"}, Usage: "send some text"},
&cli.BoolFlag{Name: "no-local", Usage: "disable local relay when sending"},
&cli.BoolFlag{Name: "no-multi", Usage: "disable multiplexing"},
&cli.BoolFlag{Name: "git", Usage: "enable .gitignore respect / don't send ignored files"},
&cli.IntFlag{Name: "port", Value: 9009, Usage: "base port for the relay"},
&cli.IntFlag{Name: "transfers", Value: 4, Usage: "number of ports to use for transfers"},
},
HelpName: "croc send",
Action: send,
},
{
Name: "relay",
Usage: "start your own relay (optional)",
Description: "start relay",
HelpName: "croc relay",
Action: relay,
Flags: []cli.Flag{
&cli.StringFlag{Name: "host", Usage: "host of the relay"},
&cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the relay"},
},
},
}
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: "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: "debug", Usage: "toggle debug mode"},
&cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
&cli.BoolFlag{Name: "stdout", Usage: "redirect file to stdout"},
&cli.BoolFlag{Name: "no-compress", Usage: "disable compression"},
&cli.BoolFlag{Name: "ask", Usage: "make sure sender and recipient are prompted"},
&cli.BoolFlag{Name: "local", Usage: "force to use only local connections"},
&cli.BoolFlag{Name: "ignore-stdin", Usage: "ignore piped stdin"},
&cli.BoolFlag{Name: "overwrite", Usage: "do not prompt to overwrite"},
&cli.BoolFlag{Name: "testing", Usage: "flag for testing purposes"},
&cli.StringFlag{Name: "curve", Value: "p256", Usage: "choose an encryption curve (" + strings.Join(pake.AvailableCurves(), ", ") + ")"},
&cli.StringFlag{Name: "ip", Value: "", Usage: "set sender ip if known e.g. 10.0.0.1:9009, [::1]:9009"},
&cli.StringFlag{Name: "relay", Value: models.DEFAULT_RELAY, Usage: "address of the relay", EnvVars: []string{"CROC_RELAY"}},
&cli.StringFlag{Name: "relay6", Value: models.DEFAULT_RELAY6, Usage: "ipv6 address of the relay", EnvVars: []string{"CROC_RELAY6"}},
&cli.StringFlag{Name: "out", Value: ".", Usage: "specify an output folder to receive the file"},
&cli.StringFlag{Name: "pass", Value: models.DEFAULT_PASSPHRASE, Usage: "password for the relay", EnvVars: []string{"CROC_PASS"}},
&cli.StringFlag{Name: "socks5", Value: "", Usage: "add a socks5 proxy", EnvVars: []string{"SOCKS5_PROXY"}},
&cli.StringFlag{Name: "connect", Value: "", Usage: "add a http proxy", EnvVars: []string{"HTTP_PROXY"}},
&cli.StringFlag{Name: "throttleUpload", Value: "", Usage: "Throttle the upload speed e.g. 500k"},
}
app.EnableBashCompletion = true
app.HideHelp = false
app.HideVersion = false
app.Action = func(c *cli.Context) error {
allStringsAreFiles := func(strs []string) bool {
for _, str := range strs {
if !utils.Exists(str) {
return false
}
}
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 c.Args().Present() && allStringsAreFiles(c.Args().Slice()) {
fnames := []string{}
for _, fpath := range c.Args().Slice() {
_, basename := filepath.Split(fpath)
fnames = append(fnames, "'"+basename+"'")
}
promptMessage := fmt.Sprintf("Did you mean to send %s? (Y/n) ", strings.Join(fnames, ", "))
choice := strings.ToLower(utils.GetInput(promptMessage))
if choice == "" || choice == "y" || choice == "yes" {
return send(c)
}
}
return receive(c)
}
return app.Run(os.Args)
}
func setDebugLevel(c *cli.Context) {
if c.Bool("debug") {
log.SetLevel("debug")
log.Debug("debug mode on")
} else {
log.SetLevel("info")
}
}
func getSendConfigFile(requireValidPath bool) string {
configFile, err := utils.GetConfigDir(requireValidPath)
if err != nil {
log.Error(err)
return ""
}
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) {
pass = c.String("pass")
b, err := os.ReadFile(pass)
if err == nil {
pass = strings.TrimSpace(string(b))
}
return
}
func send(c *cli.Context) (err error) {
setDebugLevel(c)
comm.Socks5Proxy = c.String("socks5")
comm.HttpProxy = c.String("connect")
portParam := c.Int("port")
if portParam == 0 {
portParam = 9009
}
transfersParam := c.Int("transfers")
if transfersParam == 0 {
transfersParam = 4
}
ports := make([]string, transfersParam+1)
for i := 0; i <= transfersParam; i++ {
ports[i] = strconv.Itoa(portParam + i)
}
crocOptions := croc.Options{
SharedSecret: c.String("code"),
IsSender: true,
Debug: c.Bool("debug"),
NoPrompt: c.Bool("yes"),
RelayAddress: c.String("relay"),
RelayAddress6: c.String("relay6"),
Stdout: c.Bool("stdout"),
DisableLocal: c.Bool("no-local"),
OnlyLocal: c.Bool("local"),
IgnoreStdin: c.Bool("ignore-stdin"),
RelayPorts: ports,
Ask: c.Bool("ask"),
NoMultiplexing: c.Bool("no-multi"),
RelayPassword: determinePass(c),
SendingText: c.String("text") != "",
NoCompress: c.Bool("no-compress"),
Overwrite: c.Bool("overwrite"),
Curve: c.String("curve"),
HashAlgorithm: c.String("hash"),
ThrottleUpload: c.String("throttleUpload"),
ZipFolder: c.Bool("zip"),
GitIgnore: c.Bool("git"),
}
if crocOptions.RelayAddress != models.DEFAULT_RELAY {
crocOptions.RelayAddress6 = ""
} else if crocOptions.RelayAddress6 != models.DEFAULT_RELAY6 {
crocOptions.RelayAddress = ""
}
b, errOpen := os.ReadFile(getSendConfigFile(false))
if errOpen == nil && !c.Bool("remember") {
var rememberedOptions croc.Options
err = json.Unmarshal(b, &rememberedOptions)
if err != nil {
log.Error(err)
return
}
// update anything that isn't explicitly set
if !c.IsSet("relay") && rememberedOptions.RelayAddress != "" {
crocOptions.RelayAddress = rememberedOptions.RelayAddress
}
if !c.IsSet("no-local") {
crocOptions.DisableLocal = rememberedOptions.DisableLocal
}
if !c.IsSet("ports") && len(rememberedOptions.RelayPorts) > 0 {
crocOptions.RelayPorts = rememberedOptions.RelayPorts
}
if !c.IsSet("code") {
crocOptions.SharedSecret = rememberedOptions.SharedSecret
}
if !c.IsSet("pass") && rememberedOptions.RelayPassword != "" {
crocOptions.RelayPassword = rememberedOptions.RelayPassword
}
if !c.IsSet("relay6") && rememberedOptions.RelayAddress6 != "" {
crocOptions.RelayAddress6 = rememberedOptions.RelayAddress6
}
if !c.IsSet("overwrite") {
crocOptions.Overwrite = rememberedOptions.Overwrite
}
if !c.IsSet("curve") && rememberedOptions.Curve != "" {
crocOptions.Curve = rememberedOptions.Curve
}
if !c.IsSet("local") {
crocOptions.OnlyLocal = rememberedOptions.OnlyLocal
}
if !c.IsSet("hash") {
crocOptions.HashAlgorithm = rememberedOptions.HashAlgorithm
}
if !c.IsSet("git") {
crocOptions.GitIgnore = rememberedOptions.GitIgnore
}
}
var fnames []string
stat, _ := os.Stdin.Stat()
if ((stat.Mode() & os.ModeCharDevice) == 0) && !c.Bool("ignore-stdin") {
fnames, err = getStdin()
if err != nil {
return
}
defer func() {
e := os.Remove(fnames[0])
if e != nil {
log.Error(e)
}
}()
} else if c.String("text") != "" {
fnames, err = makeTempFileWithString(c.String("text"))
if err != nil {
return
}
defer func() {
e := os.Remove(fnames[0])
if e != nil {
log.Error(e)
}
}()
} else {
fnames = c.Args().Slice()
}
if len(fnames) == 0 {
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 {
// generate code phrase
crocOptions.SharedSecret = utils.GetRandomName()
}
minimalFileInfos, emptyFoldersToTransfer, totalNumberFolders, err := croc.GetFilesInfo(fnames, crocOptions.ZipFolder, crocOptions.GitIgnore)
if err != nil {
return
}
cr, err := croc.New(crocOptions)
if err != nil {
return
}
// save the config
saveConfig(c, crocOptions)
err = cr.Send(minimalFileInfos, emptyFoldersToTransfer, totalNumberFolders)
return
}
func getStdin() (fnames []string, err error) {
f, err := os.CreateTemp(".", "croc-stdin-")
if err != nil {
return
}
_, err = io.Copy(f, os.Stdin)
if err != nil {
return
}
err = f.Close()
if err != nil {
return
}
fnames = []string{f.Name()}
return
}
func makeTempFileWithString(s string) (fnames []string, err error) {
f, err := os.CreateTemp(".", "croc-stdin-")
if err != nil {
return
}
_, err = f.WriteString(s)
if err != nil {
return
}
err = f.Close()
if err != nil {
return
}
fnames = []string{f.Name()}
return
}
func saveConfig(c *cli.Context, crocOptions croc.Options) {
if c.Bool("remember") {
configFile := getSendConfigFile(true)
log.Debug("saving config file")
var bConfig []byte
// if the code wasn't set, don't save it
if c.String("code") == "" {
crocOptions.SharedSecret = ""
}
bConfig, err := json.MarshalIndent(crocOptions, "", " ")
if err != nil {
log.Error(err)
return
}
err = os.WriteFile(configFile, bConfig, 0o644)
if err != nil {
log.Error(err)
return
}
log.Debugf("wrote %s", configFile)
}
}
type TabComplete struct{}
func (t TabComplete) Do(line []rune, pos int) ([][]rune, int) {
var words = strings.SplitAfter(string(line), "-")
var lastPartialWord = words[len(words)-1]
var nbCharacter = len(lastPartialWord)
if nbCharacter == 0 {
// No completion
return [][]rune{[]rune("")}, 0
}
if len(words) == 1 && nbCharacter == utils.NbPinNumbers {
// Check if word is indeed a number
_, err := strconv.Atoi(lastPartialWord)
if err == nil {
return [][]rune{[]rune("-")}, nbCharacter
}
}
var strArray [][]rune
for _, s := range mnemonicode.WordList {
if strings.HasPrefix(s, lastPartialWord) {
var completionCandidate = s[nbCharacter:]
if len(words) <= mnemonicode.WordsRequired(utils.NbBytesWords) {
completionCandidate += "-"
}
strArray = append(strArray, []rune(completionCandidate))
}
}
return strArray, nbCharacter
}
func receive(c *cli.Context) (err error) {
comm.Socks5Proxy = c.String("socks5")
comm.HttpProxy = c.String("connect")
crocOptions := croc.Options{
SharedSecret: c.String("code"),
IsSender: false,
Debug: c.Bool("debug"),
NoPrompt: c.Bool("yes"),
RelayAddress: c.String("relay"),
RelayAddress6: c.String("relay6"),
Stdout: c.Bool("stdout"),
Ask: c.Bool("ask"),
RelayPassword: determinePass(c),
OnlyLocal: c.Bool("local"),
IP: c.String("ip"),
Overwrite: c.Bool("overwrite"),
Curve: c.String("curve"),
TestFlag: c.Bool("testing"),
}
if crocOptions.RelayAddress != models.DEFAULT_RELAY {
crocOptions.RelayAddress6 = ""
} else if crocOptions.RelayAddress6 != models.DEFAULT_RELAY6 {
crocOptions.RelayAddress = ""
}
switch c.Args().Len() {
case 1:
crocOptions.SharedSecret = c.Args().First()
case 3:
fallthrough
case 4:
var phrase []string
phrase = append(phrase, c.Args().First())
phrase = append(phrase, c.Args().Tail()...)
crocOptions.SharedSecret = strings.Join(phrase, "-")
}
// load options here
setDebugLevel(c)
doRemember := c.Bool("remember")
configFile, err := getReceiveConfigFile(doRemember)
if err != nil && doRemember {
return
}
b, errOpen := os.ReadFile(configFile)
if errOpen == nil && !doRemember {
var rememberedOptions croc.Options
err = json.Unmarshal(b, &rememberedOptions)
if err != nil {
log.Error(err)
return
}
// update anything that isn't explicitly Globally set
if !c.IsSet("relay") && rememberedOptions.RelayAddress != "" {
crocOptions.RelayAddress = rememberedOptions.RelayAddress
}
if !c.IsSet("yes") {
crocOptions.NoPrompt = rememberedOptions.NoPrompt
}
if crocOptions.SharedSecret == "" {
crocOptions.SharedSecret = rememberedOptions.SharedSecret
}
if !c.IsSet("pass") && rememberedOptions.RelayPassword != "" {
crocOptions.RelayPassword = rememberedOptions.RelayPassword
}
if !c.IsSet("relay6") && rememberedOptions.RelayAddress6 != "" {
crocOptions.RelayAddress6 = rememberedOptions.RelayAddress6
}
if !c.IsSet("overwrite") {
crocOptions.Overwrite = rememberedOptions.Overwrite
}
if !c.IsSet("curve") && rememberedOptions.Curve != "" {
crocOptions.Curve = rememberedOptions.Curve
}
if !c.IsSet("local") {
crocOptions.OnlyLocal = rememberedOptions.OnlyLocal
}
}
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 == "" {
l, err := readline.NewEx(&readline.Config{
Prompt: "Enter receive code: ",
AutoComplete: TabComplete{},
})
if err != nil {
return err
}
crocOptions.SharedSecret, err = l.Readline()
if err != nil {
return err
}
}
if c.String("out") != "" {
if err = os.Chdir(c.String("out")); err != nil {
return err
}
}
cr, err := croc.New(crocOptions)
if err != nil {
return
}
// save the config
if doRemember {
log.Debug("saving config file")
var bConfig []byte
bConfig, err = json.MarshalIndent(crocOptions, "", " ")
if err != nil {
log.Error(err)
return
}
err = os.WriteFile(configFile, bConfig, 0o644)
if err != nil {
log.Error(err)
return
}
log.Debugf("wrote %s", configFile)
}
err = cr.Receive()
return
}
func relay(c *cli.Context) (err error) {
log.Infof("starting croc relay version %v", Version)
debugString := "info"
if c.Bool("debug") {
debugString = "debug"
}
host := c.String("host")
ports := strings.Split(c.String("ports"), ",")
tcpPorts := strings.Join(ports[1:], ",")
for i, port := range ports {
if i == 0 {
continue
}
go func(portStr string) {
err := tcp.Run(debugString, host, portStr, determinePass(c))
if err != nil {
panic(err)
}
}(port)
}
return tcp.Run(debugString, host, ports[0], determinePass(c), tcpPorts)
}

200
src/comm/comm.go Normal file
View File

@ -0,0 +1,200 @@
package comm
import (
"bytes"
"encoding/binary"
"fmt"
"io"
"net"
"net/url"
"strings"
"time"
"github.com/magisterquis/connectproxy"
"github.com/schollz/croc/v10/src/utils"
log "github.com/schollz/logger"
"golang.org/x/net/proxy"
)
var Socks5Proxy = ""
var HttpProxy = ""
var MAGIC_BYTES = []byte("croc")
// Comm is some basic TCP communication
type Comm struct {
connection net.Conn
}
// NewConnection gets a new comm to a tcp address
func NewConnection(address string, timelimit ...time.Duration) (c *Comm, err error) {
tlimit := 30 * time.Second
if len(timelimit) > 0 {
tlimit = timelimit[0]
}
var connection net.Conn
if Socks5Proxy != "" && !utils.IsLocalIP(address) {
var dialer proxy.Dialer
// prepend schema if no schema is given
if !strings.Contains(Socks5Proxy, `://`) {
Socks5Proxy = `socks5://` + Socks5Proxy
}
socks5ProxyURL, urlParseError := url.Parse(Socks5Proxy)
if urlParseError != nil {
err = fmt.Errorf("unable to parse socks proxy url: %s", urlParseError)
log.Debug(err)
return
}
dialer, err = proxy.FromURL(socks5ProxyURL, proxy.Direct)
if err != nil {
err = fmt.Errorf("proxy failed: %w", err)
log.Debug(err)
return
}
log.Debug("dialing with dialer.Dial")
connection, err = dialer.Dial("tcp", address)
} else if HttpProxy != "" && !utils.IsLocalIP(address) {
var dialer proxy.Dialer
// prepend schema if no schema is given
if !strings.Contains(HttpProxy, `://`) {
HttpProxy = `http://` + HttpProxy
}
HttpProxyURL, urlParseError := url.Parse(HttpProxy)
if urlParseError != nil {
err = fmt.Errorf("unable to parse http proxy url: %s", urlParseError)
log.Debug(err)
return
}
dialer, err = connectproxy.New(HttpProxyURL, proxy.Direct)
if err != nil {
err = fmt.Errorf("proxy failed: %w", err)
log.Debug(err)
return
}
log.Debug("dialing with dialer.Dial")
connection, err = dialer.Dial("tcp", address)
} else {
log.Debugf("dialing to %s with timelimit %s", address, tlimit)
connection, err = net.DialTimeout("tcp", address, tlimit)
}
if err != nil {
err = fmt.Errorf("comm.NewConnection failed: %w", err)
log.Debug(err)
return
}
c = New(connection)
log.Debugf("connected to '%s'", address)
return
}
// New returns a new comm
func New(c net.Conn) *Comm {
if err := c.SetReadDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Warnf("error setting read deadline: %v", err)
}
if err := c.SetDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Warnf("error setting overall deadline: %v", err)
}
if err := c.SetWriteDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Errorf("error setting write deadline: %v", err)
}
comm := new(Comm)
comm.connection = c
return comm
}
// Connection returns the net.Conn connection
func (c *Comm) Connection() net.Conn {
return c.connection
}
// Close closes the connection
func (c *Comm) Close() {
if err := c.connection.Close(); err != nil {
log.Warnf("error closing connection: %v", err)
}
}
func (c *Comm) Write(b []byte) (n int, err error) {
header := new(bytes.Buffer)
err = binary.Write(header, binary.LittleEndian, uint32(len(b)))
if err != nil {
fmt.Println("binary.Write failed:", err)
}
tmpCopy := append(header.Bytes(), b...)
tmpCopy = append(MAGIC_BYTES, tmpCopy...)
n, err = c.connection.Write(tmpCopy)
if err != nil {
err = fmt.Errorf("connection.Write failed: %w", err)
return
}
if n != len(tmpCopy) {
err = fmt.Errorf("wanted to write %d but wrote %d", len(b), n)
return
}
return
}
func (c *Comm) Read() (buf []byte, numBytes int, bs []byte, err error) {
// long read deadline in case waiting for file
if err = c.connection.SetReadDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Warnf("error setting read deadline: %v", err)
}
// must clear the timeout setting
defer c.connection.SetDeadline(time.Time{})
// read until we get 4 bytes for the magic
header := make([]byte, 4)
_, err = io.ReadFull(c.connection, header)
if err != nil {
log.Debugf("initial read error: %v", err)
return
}
if !bytes.Equal(header, MAGIC_BYTES) {
err = fmt.Errorf("initial bytes are not magic: %x", header)
return
}
// read until we get 4 bytes for the header
header = make([]byte, 4)
_, err = io.ReadFull(c.connection, header)
if err != nil {
log.Debugf("initial read error: %v", err)
return
}
var numBytesUint32 uint32
rbuf := bytes.NewReader(header)
err = binary.Read(rbuf, binary.LittleEndian, &numBytesUint32)
if err != nil {
err = fmt.Errorf("binary.Read failed: %w", err)
log.Debug(err.Error())
return
}
numBytes = int(numBytesUint32)
// shorten the reading deadline in case getting weird data
if err = c.connection.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
log.Warnf("error setting read deadline: %v", err)
}
buf = make([]byte, numBytes)
_, err = io.ReadFull(c.connection, buf)
if err != nil {
log.Debugf("consecutive read error: %v", err)
return
}
return
}
// Send a message
func (c *Comm) Send(message []byte) (err error) {
_, err = c.Write(message)
return
}
// Receive a message
func (c *Comm) Receive() (b []byte, err error) {
b, _, _, err = c.Read()
return
}

66
src/comm/comm_test.go Normal file
View File

@ -0,0 +1,66 @@
package comm
import (
"crypto/rand"
"net"
"testing"
"time"
log "github.com/schollz/logger"
"github.com/stretchr/testify/assert"
)
func TestComm(t *testing.T) {
token := make([]byte, 3000)
if _, err := rand.Read(token); err != nil {
t.Error(err)
}
port := "8001"
go func() {
log.Debugf("starting TCP server on " + port)
server, err := net.Listen("tcp", "0.0.0.0:"+port)
if err != nil {
log.Error(err)
}
defer server.Close()
// spawn a new goroutine whenever a client connects
for {
connection, err := server.Accept()
if err != nil {
log.Error(err)
}
log.Debugf("client %s connected", connection.RemoteAddr().String())
go func(_ string, connection net.Conn) {
c := New(connection)
err = c.Send([]byte("hello, world"))
assert.Nil(t, err)
data, err := c.Receive()
assert.Nil(t, err)
assert.Equal(t, []byte("hello, computer"), data)
data, err = c.Receive()
assert.Nil(t, err)
assert.Equal(t, []byte{'\x00'}, data)
data, err = c.Receive()
assert.Nil(t, err)
assert.Equal(t, token, data)
}(port, connection)
}
}()
time.Sleep(300 * time.Millisecond)
a, err := NewConnection("127.0.0.1:"+port, 10*time.Minute)
assert.Nil(t, err)
data, err := a.Receive()
assert.Equal(t, []byte("hello, world"), data)
assert.Nil(t, err)
assert.Nil(t, a.Send([]byte("hello, computer")))
assert.Nil(t, a.Send([]byte{'\x00'}))
assert.Nil(t, a.Send(token))
_ = a.Connection()
a.Close()
assert.NotNil(t, a.Send(token))
_, err = a.Write(token)
assert.NotNil(t, err)
}

53
src/compress/compress.go Normal file
View File

@ -0,0 +1,53 @@
package compress
import (
"bytes"
"compress/flate"
"io"
log "github.com/schollz/logger"
)
// CompressWithOption returns compressed data using the specified level
func CompressWithOption(src []byte, level int) []byte {
compressedData := new(bytes.Buffer)
compress(src, compressedData, level)
return compressedData.Bytes()
}
// Compress returns a compressed byte slice.
func Compress(src []byte) []byte {
compressedData := new(bytes.Buffer)
compress(src, compressedData, -2)
return compressedData.Bytes()
}
// Decompress returns a decompressed byte slice.
func Decompress(src []byte) []byte {
compressedData := bytes.NewBuffer(src)
deCompressedData := new(bytes.Buffer)
decompress(compressedData, deCompressedData)
return deCompressedData.Bytes()
}
// compress uses flate to compress a byte slice to a corresponding level
func compress(src []byte, dest io.Writer, level int) {
compressor, err := flate.NewWriter(dest, level)
if err != nil {
log.Debugf("error level data: %v", err)
return
}
if _, err := compressor.Write(src); err != nil {
log.Debugf("error writing data: %v", err)
}
compressor.Close()
}
// compress uses flate to decompress an io.Reader
func decompress(src io.Reader, dest io.Writer) {
decompressor := flate.NewReader(src)
if _, err := io.Copy(dest, decompressor); err != nil {
log.Debugf("error copying data: %v", err)
}
decompressor.Close()
}

View File

@ -0,0 +1,105 @@
package compress
import (
"crypto/rand"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
var fable = []byte(`The Frog and the Crocodile
Once, there was a frog who lived in the middle of a swamp. His entire family had lived in that swamp for generations, but this particular frog decided that he had had quite enough wetness to last him a lifetime. He decided that he was going to find a dry place to live instead.
The only thing that separated him from dry land was a swampy, muddy, swiftly flowing river. But the river was home to all sorts of slippery, slittering snakes that loved nothing better than a good, plump frog for dinner, so Frog didn't dare try to swim across.
So for many days, the frog stayed put, hopping along the bank, trying to think of a way to get across.
The snakes hissed and jeered at him, daring him to come closer, but he refused. Occasionally they would slither closer, jaws open to attack, but the frog always leaped out of the way. But no matter how far upstream he searched or how far downstream, the frog wasn't able to find a way across the water.
He had felt certain that there would be a bridge, or a place where the banks came together, yet all he found was more reeds and water. After a while, even the snakes stopped teasing him and went off in search of easier prey.
The frog sighed in frustration and sat to sulk in the rushes. Suddenly, he spotted two big eyes staring at him from the water. The giant log-shaped animal opened its mouth and asked him, "What are you doing, Frog? Surely there are enough flies right there for a meal."
The frog croaked in surprise and leaped away from the crocodile. That creature could swallow him whole in a moment without thinking about it! Once he was a satisfied that he was a safe distance away, he answered. "I'm tired of living in swampy waters, and I want to travel to the other side of the river. But if I swim across, the snakes will eat me."
The crocodile harrumphed in agreement and sat, thinking, for a while. "Well, if you're afraid of the snakes, I could give you a ride across," he suggested.
"Oh no, I don't think so," Frog answered quickly. "You'd eat me on the way over, or go underwater so the snakes could get me!"
"Now why would I let the snakes get you? I think they're a terrible nuisance with all their hissing and slithering! The river would be much better off without them altogether! Anyway, if you're so worried that I might eat you, you can ride on my tail."
The frog considered his offer. He did want to get to dry ground very badly, and there didn't seem to be any other way across the river. He looked at the crocodile from his short, squat buggy eyes and wondered about the crocodile's motives. But if he rode on the tail, the croc couldn't eat him anyway. And he was right about the snakes--no self-respecting crocodile would give a meal to the snakes.
"Okay, it sounds like a good plan to me. Turn around so I can hop on your tail."
The crocodile flopped his tail into the marshy mud and let the frog climb on, then he waddled out to the river. But he couldn't stick his tail into the water as a rudder because the frog was on it -- and if he put his tail in the water, the snakes would eat the frog. They clumsily floated downstream for a ways, until the crocodile said, "Hop onto my back so I can steer straight with my tail." The frog moved, and the journey smoothed out.
From where he was sitting, the frog couldn't see much except the back of Crocodile's head. "Why don't you hop up on my head so you can see everything around us?" Crocodile invited. `)
func BenchmarkCompressLevelMinusTwo(b *testing.B) {
for i := 0; i < b.N; i++ {
CompressWithOption(fable, -2)
}
}
func BenchmarkCompressLevelNine(b *testing.B) {
for i := 0; i < b.N; i++ {
CompressWithOption(fable, 9)
}
}
func BenchmarkCompressLevelMinusTwoBinary(b *testing.B) {
data := make([]byte, 1000000)
if _, err := rand.Read(data); err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
CompressWithOption(data, -2)
}
}
func BenchmarkCompressLevelNineBinary(b *testing.B) {
data := make([]byte, 1000000)
if _, err := rand.Read(data); err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
CompressWithOption(data, 9)
}
}
func TestCompress(t *testing.T) {
compressedB := CompressWithOption(fable, 9)
dataRateSavings := 100 * (1.0 - float64(len(compressedB))/float64(len(fable)))
fmt.Printf("Level 9: %2.0f%% percent space savings\n", dataRateSavings)
assert.True(t, len(compressedB) < len(fable))
assert.Equal(t, fable, Decompress(compressedB))
compressedB = CompressWithOption(fable, -2)
dataRateSavings = 100 * (1.0 - float64(len(compressedB))/float64(len(fable)))
fmt.Printf("Level -2: %2.0f%% percent space savings\n", dataRateSavings)
assert.True(t, len(compressedB) < len(fable))
compressedB = Compress(fable)
dataRateSavings = 100 * (1.0 - float64(len(compressedB))/float64(len(fable)))
fmt.Printf("Level -2: %2.0f%% percent space savings\n", dataRateSavings)
assert.True(t, len(compressedB) < len(fable))
data := make([]byte, 4096)
if _, err := rand.Read(data); err != nil {
t.Fatal(err)
}
compressedB = CompressWithOption(data, -2)
dataRateSavings = 100 * (1.0 - float64(len(compressedB))/float64(len(data)))
fmt.Printf("random, Level -2: %2.0f%% percent space savings\n", dataRateSavings)
if _, err := rand.Read(data); err != nil {
t.Fatal(err)
}
compressedB = CompressWithOption(data, 9)
dataRateSavings = 100 * (1.0 - float64(len(compressedB))/float64(len(data)))
fmt.Printf("random, Level 9: %2.0f%% percent space savings\n", dataRateSavings)
}

2076
src/croc/croc.go Normal file

File diff suppressed because it is too large Load Diff

400
src/croc/croc_test.go Normal file
View File

@ -0,0 +1,400 @@
package croc
import (
"os"
"path"
"path/filepath"
"runtime"
"strings"
"sync"
"testing"
"time"
"github.com/schollz/croc/v10/src/tcp"
log "github.com/schollz/logger"
"github.com/stretchr/testify/assert"
)
func init() {
log.SetLevel("trace")
go tcp.Run("debug", "127.0.0.1", "8281", "pass123", "8282,8283,8284,8285")
go tcp.Run("debug", "127.0.0.1", "8282", "pass123")
go tcp.Run("debug", "127.0.0.1", "8283", "pass123")
go tcp.Run("debug", "127.0.0.1", "8284", "pass123")
go tcp.Run("debug", "127.0.0.1", "8285", "pass123")
time.Sleep(1 * time.Second)
}
func TestCrocReadme(t *testing.T) {
defer os.Remove("README.md")
log.Debug("setting up sender")
sender, err := New(Options{
IsSender: true,
SharedSecret: "8123-testingthecroc",
Debug: true,
RelayAddress: "127.0.0.1:8281",
RelayPorts: []string{"8281"},
RelayPassword: "pass123",
Stdout: false,
NoPrompt: true,
DisableLocal: true,
Curve: "siec",
Overwrite: true,
GitIgnore: false,
})
if err != nil {
panic(err)
}
log.Debug("setting up receiver")
receiver, err := New(Options{
IsSender: false,
SharedSecret: "8123-testingthecroc",
Debug: true,
RelayAddress: "127.0.0.1:8281",
RelayPassword: "pass123",
Stdout: false,
NoPrompt: true,
DisableLocal: true,
Curve: "siec",
Overwrite: true,
})
if err != nil {
panic(err)
}
var wg sync.WaitGroup
wg.Add(2)
go func() {
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{"../../README.md"}, false, false)
if errGet != nil {
t.Errorf("failed to get minimal info: %v", errGet)
}
err := sender.Send(filesInfo, emptyFolders, totalNumberFolders)
if err != nil {
t.Errorf("send failed: %v", err)
}
wg.Done()
}()
time.Sleep(100 * time.Millisecond)
go func() {
err := receiver.Receive()
if err != nil {
t.Errorf("receive failed: %v", err)
}
wg.Done()
}()
wg.Wait()
}
func TestCrocEmptyFolder(t *testing.T) {
pathName := "../../testEmpty"
defer os.RemoveAll(pathName)
defer os.RemoveAll("./testEmpty")
os.MkdirAll(pathName, 0o755)
log.Debug("setting up sender")
sender, err := New(Options{
IsSender: true,
SharedSecret: "8123-testingthecroc",
Debug: true,
RelayAddress: "127.0.0.1:8281",
RelayPorts: []string{"8281"},
RelayPassword: "pass123",
Stdout: false,
NoPrompt: true,
DisableLocal: true,
Curve: "siec",
Overwrite: true,
})
if err != nil {
panic(err)
}
log.Debug("setting up receiver")
receiver, err := New(Options{
IsSender: false,
SharedSecret: "8123-testingthecroc",
Debug: true,
RelayAddress: "127.0.0.1:8281",
RelayPassword: "pass123",
Stdout: false,
NoPrompt: true,
DisableLocal: true,
Curve: "siec",
Overwrite: true,
})
if err != nil {
panic(err)
}
var wg sync.WaitGroup
wg.Add(2)
go func() {
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{pathName}, false, false)
if errGet != nil {
t.Errorf("failed to get minimal info: %v", errGet)
}
err := sender.Send(filesInfo, emptyFolders, totalNumberFolders)
if err != nil {
t.Errorf("send failed: %v", err)
}
wg.Done()
}()
time.Sleep(100 * time.Millisecond)
go func() {
err := receiver.Receive()
if err != nil {
t.Errorf("receive failed: %v", err)
}
wg.Done()
}()
wg.Wait()
}
func TestCrocSymlink(t *testing.T) {
pathName := "../link-in-folder"
defer os.RemoveAll(pathName)
defer os.RemoveAll("./link-in-folder")
os.MkdirAll(pathName, 0o755)
os.Symlink("../../README.md", filepath.Join(pathName, "README.link"))
log.Debug("setting up sender")
sender, err := New(Options{
IsSender: true,
SharedSecret: "8124-testingthecroc",
Debug: true,
RelayAddress: "127.0.0.1:8281",
RelayPorts: []string{"8281"},
RelayPassword: "pass123",
Stdout: false,
NoPrompt: true,
DisableLocal: true,
Curve: "siec",
Overwrite: true,
GitIgnore: false,
})
if err != nil {
panic(err)
}
log.Debug("setting up receiver")
receiver, err := New(Options{
IsSender: false,
SharedSecret: "8124-testingthecroc",
Debug: true,
RelayAddress: "127.0.0.1:8281",
RelayPassword: "pass123",
Stdout: false,
NoPrompt: true,
DisableLocal: true,
Curve: "siec",
Overwrite: true,
})
if err != nil {
panic(err)
}
var wg sync.WaitGroup
wg.Add(2)
go func() {
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{pathName}, false, false)
if errGet != nil {
t.Errorf("failed to get minimal info: %v", errGet)
}
err = sender.Send(filesInfo, emptyFolders, totalNumberFolders)
if err != nil {
t.Errorf("send failed: %v", err)
}
wg.Done()
}()
time.Sleep(100 * time.Millisecond)
go func() {
err = receiver.Receive()
if err != nil {
t.Errorf("receive failed: %v", err)
}
wg.Done()
}()
wg.Wait()
s, err := filepath.EvalSymlinks(path.Join(pathName, "README.link"))
if s != "../../README.md" && s != "..\\..\\README.md" {
log.Debug(s)
t.Errorf("symlink failed to transfer in folder")
}
if err != nil {
t.Errorf("symlink transfer failed: %s", err.Error())
}
}
func testCrocIgnoreGit(t *testing.T) {
log.SetLevel("trace")
defer os.Remove(".gitignore")
time.Sleep(300 * time.Millisecond)
time.Sleep(1 * time.Second)
file, err := os.Create(".gitignore")
if err != nil {
log.Errorf("error creating file")
}
_, err = file.WriteString("LICENSE")
if err != nil {
log.Errorf("error writing to file")
}
time.Sleep(1 * time.Second)
// due to how files are ignored in this function, all we have to do to test is make sure LICENSE doesn't get included in FilesInfo.
filesInfo, _, _, errGet := GetFilesInfo([]string{"../../LICENSE", ".gitignore", "croc.go"}, false, true)
if errGet != nil {
t.Errorf("failed to get minimal info: %v", errGet)
}
for _, file := range filesInfo {
if strings.Contains(file.Name, "LICENSE") {
t.Errorf("test failed, should ignore LICENSE")
}
}
}
func TestCrocLocal(t *testing.T) {
log.SetLevel("trace")
defer os.Remove("LICENSE")
defer os.Remove("touched")
time.Sleep(300 * time.Millisecond)
log.Debug("setting up sender")
sender, err := New(Options{
IsSender: true,
SharedSecret: "8123-testingthecroc",
Debug: true,
RelayAddress: "127.0.0.1:8181",
RelayPorts: []string{"8181", "8182"},
RelayPassword: "pass123",
Stdout: true,
NoPrompt: true,
DisableLocal: false,
Curve: "siec",
Overwrite: true,
GitIgnore: false,
})
if err != nil {
panic(err)
}
time.Sleep(1 * time.Second)
log.Debug("setting up receiver")
receiver, err := New(Options{
IsSender: false,
SharedSecret: "8123-testingthecroc",
Debug: true,
RelayAddress: "127.0.0.1:8181",
RelayPassword: "pass123",
Stdout: true,
NoPrompt: true,
DisableLocal: false,
Curve: "siec",
Overwrite: true,
})
if err != nil {
panic(err)
}
var wg sync.WaitGroup
os.Create("touched")
wg.Add(2)
go func() {
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{"../../LICENSE", "touched"}, false, false)
if errGet != nil {
t.Errorf("failed to get minimal info: %v", errGet)
}
err := sender.Send(filesInfo, emptyFolders, totalNumberFolders)
if err != nil {
t.Errorf("send failed: %v", err)
}
wg.Done()
}()
time.Sleep(100 * time.Millisecond)
go func() {
err := receiver.Receive()
if err != nil {
t.Errorf("send failed: %v", err)
}
wg.Done()
}()
wg.Wait()
}
func TestCrocError(t *testing.T) {
content := []byte("temporary file's content")
tmpfile, err := os.CreateTemp("", "example")
if err != nil {
panic(err)
}
defer os.Remove(tmpfile.Name()) // clean up
if _, err = tmpfile.Write(content); err != nil {
panic(err)
}
if err = tmpfile.Close(); err != nil {
panic(err)
}
Debug(false)
log.SetLevel("warn")
sender, _ := New(Options{
IsSender: true,
SharedSecret: "8123-testingthecroc2",
Debug: true,
RelayAddress: "doesntexistok.com:8381",
RelayPorts: []string{"8381", "8382"},
RelayPassword: "pass123",
Stdout: true,
NoPrompt: true,
DisableLocal: true,
Curve: "siec",
Overwrite: true,
})
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{tmpfile.Name()}, false, false)
if errGet != nil {
t.Errorf("failed to get minimal info: %v", errGet)
}
err = sender.Send(filesInfo, emptyFolders, totalNumberFolders)
log.Debug(err)
assert.NotNil(t, err)
}
func TestCleanUp(t *testing.T) {
// windows allows files to be deleted only if they
// are not open by another program so the remove actions
// from the above tests will not always do a good clean up
// This "test" will make sure
operatingSystem := runtime.GOOS
log.Debugf("The operating system is %s", operatingSystem)
if operatingSystem == "windows" {
time.Sleep(1 * time.Second)
log.Debug("Full cleanup")
var err error
for _, file := range []string{"README.md", "./README.md"} {
err = os.Remove(file)
if err == nil {
log.Debugf("Successfully purged %s", file)
} else {
log.Debugf("%s was already purged.", file)
}
}
for _, folder := range []string{"./testEmpty", "./link-in-folder"} {
err = os.RemoveAll(folder)
if err == nil {
log.Debugf("Successfully purged %s", folder)
} else {
log.Debugf("%s was already purged.", folder)
}
}
}
}

125
src/crypt/crypt.go Normal file
View File

@ -0,0 +1,125 @@
package crypt
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"fmt"
"log"
"golang.org/x/crypto/argon2"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/pbkdf2"
)
// New generates a new key based on a passphrase and salt
func New(passphrase []byte, usersalt []byte) (key []byte, salt []byte, err error) {
if len(passphrase) < 1 {
err = fmt.Errorf("need more than that for passphrase")
return
}
if usersalt == nil {
salt = make([]byte, 8)
// http://www.ietf.org/rfc/rfc2898.txt
// Salt.
if _, err := rand.Read(salt); err != nil {
log.Fatalf("can't get random salt: %v", err)
}
} else {
salt = usersalt
}
key = pbkdf2.Key(passphrase, salt, 100, 32, sha256.New)
return
}
// Encrypt will encrypt using the pre-generated key
func Encrypt(plaintext []byte, key []byte) (encrypted []byte, err error) {
// generate a random iv each time
// http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
// Section 8.2
ivBytes := make([]byte, 12)
if _, err = rand.Read(ivBytes); err != nil {
log.Fatalf("can't initialize crypto: %v", err)
}
b, err := aes.NewCipher(key)
if err != nil {
return
}
aesgcm, err := cipher.NewGCM(b)
if err != nil {
return
}
encrypted = aesgcm.Seal(nil, ivBytes, plaintext, nil)
encrypted = append(ivBytes, encrypted...)
return
}
// Decrypt using the pre-generated key
func Decrypt(encrypted []byte, key []byte) (plaintext []byte, err error) {
if len(encrypted) < 13 {
err = fmt.Errorf("incorrect passphrase")
return
}
b, err := aes.NewCipher(key)
if err != nil {
return
}
aesgcm, err := cipher.NewGCM(b)
if err != nil {
return
}
plaintext, err = aesgcm.Open(nil, encrypted[:12], encrypted[12:], nil)
return
}
// NewArgon2 generates a new key based on a passphrase and salt
// using argon2
// https://pkg.go.dev/golang.org/x/crypto/argon2
func NewArgon2(passphrase []byte, usersalt []byte) (aead cipher.AEAD, salt []byte, err error) {
if len(passphrase) < 1 {
err = fmt.Errorf("need more than that for passphrase")
return
}
if usersalt == nil {
salt = make([]byte, 8)
// http://www.ietf.org/rfc/rfc2898.txt
// Salt.
if _, err = rand.Read(salt); err != nil {
log.Fatalf("can't get random salt: %v", err)
}
} else {
salt = usersalt
}
aead, err = chacha20poly1305.NewX(argon2.IDKey(passphrase, salt, 1, 64*1024, 4, 32))
return
}
// EncryptChaCha will encrypt ChaCha20-Poly1305 using the pre-generated key
// https://pkg.go.dev/golang.org/x/crypto/chacha20poly1305
func EncryptChaCha(plaintext []byte, aead cipher.AEAD) (encrypted []byte, err error) {
nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead())
if _, err := rand.Read(nonce); err != nil {
panic(err)
}
// Encrypt the message and append the ciphertext to the nonce.
encrypted = aead.Seal(nonce, nonce, plaintext, nil)
return
}
// DecryptChaCha will encrypt ChaCha20-Poly1305 using the pre-generated key
// https://pkg.go.dev/golang.org/x/crypto/chacha20poly1305
func DecryptChaCha(encryptedMsg []byte, aead cipher.AEAD) (encrypted []byte, err error) {
if len(encryptedMsg) < aead.NonceSize() {
err = fmt.Errorf("ciphertext too short")
return
}
// Split nonce and ciphertext.
nonce, ciphertext := encryptedMsg[:aead.NonceSize()], encryptedMsg[aead.NonceSize():]
// Decrypt the message and check it wasn't tampered with.
encrypted, err = aead.Open(nil, nonce, ciphertext, nil)
return
}

105
src/crypt/crypt_test.go Normal file
View File

@ -0,0 +1,105 @@
package crypt
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func BenchmarkEncrypt(b *testing.B) {
bob, _, _ := New([]byte("password"), nil)
for i := 0; i < b.N; i++ {
Encrypt([]byte("hello, world"), bob)
}
}
func BenchmarkDecrypt(b *testing.B) {
key, _, _ := New([]byte("password"), nil)
msg := []byte("hello, world")
enc, _ := Encrypt(msg, key)
b.ResetTimer()
for i := 0; i < b.N; i++ {
Decrypt(enc, key)
}
}
func BenchmarkEncryptChaCha(b *testing.B) {
bob, _, _ := NewArgon2([]byte("password"), nil)
for i := 0; i < b.N; i++ {
EncryptChaCha([]byte("hello, world"), bob)
}
}
func BenchmarkDecryptChaCha(b *testing.B) {
key, _, _ := NewArgon2([]byte("password"), nil)
msg := []byte("hello, world")
enc, _ := EncryptChaCha(msg, key)
b.ResetTimer()
for i := 0; i < b.N; i++ {
DecryptChaCha(enc, key)
}
}
func TestEncryption(t *testing.T) {
key, salt, err := New([]byte("password"), nil)
assert.Nil(t, err)
msg := []byte("hello, world")
enc, err := Encrypt(msg, key)
assert.Nil(t, err)
dec, err := Decrypt(enc, key)
assert.Nil(t, err)
assert.Equal(t, msg, dec)
// check reusing the salt
key2, _, _ := New([]byte("password"), salt)
dec, err = Decrypt(enc, key2)
assert.Nil(t, err)
assert.Equal(t, msg, dec)
// check reusing the salt
key2, _, _ = New([]byte("wrong password"), salt)
dec, err = Decrypt(enc, key2)
assert.NotNil(t, err)
assert.NotEqual(t, msg, dec)
// error with no password
_, err = Decrypt([]byte(""), key)
assert.NotNil(t, err)
// error with small password
_, _, err = New([]byte(""), nil)
assert.NotNil(t, err)
}
func TestEncryptionChaCha(t *testing.T) {
key, salt, err := NewArgon2([]byte("password"), nil)
fmt.Printf("key: %x\n", key)
assert.Nil(t, err)
msg := []byte("hello, world")
enc, err := EncryptChaCha(msg, key)
assert.Nil(t, err)
dec, err := DecryptChaCha(enc, key)
assert.Nil(t, err)
assert.Equal(t, msg, dec)
// check reusing the salt
key2, _, _ := NewArgon2([]byte("password"), salt)
dec, err = DecryptChaCha(enc, key2)
assert.Nil(t, err)
assert.Equal(t, msg, dec)
// check reusing the salt
key2, _, _ = NewArgon2([]byte("wrong password"), salt)
dec, err = DecryptChaCha(enc, key2)
assert.NotNil(t, err)
assert.NotEqual(t, msg, dec)
// error with no password
_, err = DecryptChaCha([]byte(""), key)
assert.NotNil(t, err)
// error with small password
_, _, err = NewArgon2([]byte(""), nil)
assert.NotNil(t, err)
}

19
src/install/Makefile Normal file
View File

@ -0,0 +1,19 @@
# VERSION=8.X.Y make release
release:
cd ../../ && go run src/install/updateversion.go
git commit -am "bump ${VERSION}"
git tag -af v${VERSION} -m "v${VERSION}"
git push
git push --tags
cp zsh_autocomplete ../../
cp bash_autocomplete ../../
cd ../../ && goreleaser release
cd ../../ && ./src/install/prepare-sources-tarball.sh
cd ../../ && ./src/install/upload-src-tarball.sh
test:
cp zsh_autocomplete ../../
cp bash_autocomplete ../../
cd ../../ && go generate
cd ../../ && goreleaser release --skip-publish

View File

@ -0,0 +1,19 @@
: ${PROG:=$(basename ${BASH_SOURCE})}
_cli_bash_autocomplete() {
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ "$cur" == "-"* ]]; then
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
else
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
fi
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
}
complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG
unset PROG

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 KiB

762
src/install/default.txt Normal file
View File

@ -0,0 +1,762 @@
#!/bin/bash -
#===============================================================================
#
# FILE: default.txt
#
# USAGE: curl https://getcroc.schollz.com | bash
# OR
# wget -qO- https://getcroc.schollz.com | bash
#
# DESCRIPTION: croc Installer Script.
#
# This script installs croc into a specified prefix.
# Default prefix = /usr/local/bin
#
# OPTIONS: -p, --prefix "${INSTALL_PREFIX}"
# Prefix to install croc into. Defaults to /usr/local/bin
# REQUIREMENTS: bash, uname, tar/unzip, curl/wget, sudo (if not run
# as root), install, mktemp, sha256sum/shasum/sha256
#
# BUGS: ...hopefully not. Please report.
#
# NOTES: Homepage: https://schollz.com/software/croc
# Issues: https://github.com/schollz/croc/issues
#
# CREATED: 08/10/2019 16:41
# REVISION: 0.9.2
#===============================================================================
set -o nounset # Treat unset variables as an error
#-------------------------------------------------------------------------------
# DEFAULTS
#-------------------------------------------------------------------------------
PREFIX="${PREFIX:-}"
ANDROID_ROOT="${ANDROID_ROOT:-}"
# Termux on Android has ${PREFIX} set which already ends with '/usr'
if [[ -n "${ANDROID_ROOT}" && -n "${PREFIX}" ]]; then
INSTALL_PREFIX="${PREFIX}/bin"
else
INSTALL_PREFIX="/usr/local/bin"
fi
#-------------------------------------------------------------------------------
# FUNCTIONS
#-------------------------------------------------------------------------------
#--- FUNCTION ----------------------------------------------------------------
# NAME: print_banner
# DESCRIPTION: Prints a banner
# PARAMETERS: none
# RETURNS: 0
#-------------------------------------------------------------------------------
print_banner() {
cat <<-'EOF'
=================================================
____
/ ___|_ __ ___ ___
| | | '__/ _ \ / __|
| |___| | | (_) | (__
\____|_| \___/ \___|
___ _ _ _
|_ _|_ __ ___| |_ __ _| | | ___ _ __
| || '_ \/ __| __/ _` | | |/ _ \ '__|
| || | | \__ \ || (_| | | | __/ |
|___|_| |_|___/\__\__,_|_|_|\___|_|
==================================================
EOF
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: print_help
# DESCRIPTION: Prints out a help message
# PARAMETERS: none
# RETURNS: 0
#-------------------------------------------------------------------------------
print_help() {
local help_header
local help_message
help_header="croc Installer Script"
help_message="Usage:
-p INSTALL_PREFIX
Prefix to install croc into. Directory must already exist.
Default = /usr/local/bin ('\${PREFIX}/bin' on Termux for Android)
-h
Prints this helpful message and exit."
echo "${help_header}"
echo ""
echo "${help_message}"
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: print_message
# DESCRIPTION: Prints a message all fancy like
# PARAMETERS: $1 = Message to print
# $2 = Severity. info, ok, error, warn
# RETURNS: Formatted Message to stdout
#-------------------------------------------------------------------------------
print_message() {
local message
local severity
local red
local green
local yellow
local nc
message="${1}"
severity="${2}"
red='\e[0;31m'
green='\e[0;32m'
yellow='\e[1;33m'
nc='\e[0m'
case "${severity}" in
"info" ) echo -e "${nc}${message}${nc}";;
"ok" ) echo -e "${green}${message}${nc}";;
"error" ) echo -e "${red}${message}${nc}";;
"warn" ) echo -e "${yellow}${message}${nc}";;
esac
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: make_tempdir
# DESCRIPTION: Makes a temp dir using mktemp if available
# PARAMETERS: $1 = Directory template
# RETURNS: 0 = Created temp dir. Also prints temp file path to stdout
# 1 = Failed to create temp dir
# 20 = Failed to find mktemp
#-------------------------------------------------------------------------------
make_tempdir() {
local template
local tempdir
local tempdir_rcode
template="${1}.XXXXXX"
if command -v mktemp >/dev/null 2>&1; then
tempdir="$(mktemp -d -t "${template}")"
tempdir_rcode="${?}"
if [[ "${tempdir_rcode}" == "0" ]]; then
echo "${tempdir}"
return 0
else
return 1
fi
else
return 20
fi
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: determine_os
# DESCRIPTION: Attempts to determine host os using uname
# PARAMETERS: none
# RETURNS: 0 = OS Detected. Also prints detected os to stdout
# 1 = Unknown OS
# 20 = 'uname' not found in path
#-------------------------------------------------------------------------------
determine_os() {
local uname_out
if command -v uname >/dev/null 2>&1; then
uname_out="$(uname)"
if [[ "${uname_out}" == "" ]]; then
return 1
else
echo "${uname_out}"
return 0
fi
else
return 20
fi
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: determine_arch
# DESCRIPTION: Attempt to determine architecture of host
# PARAMETERS: none
# RETURNS: 0 = Arch Detected. Also prints detected arch to stdout
# 1 = Unknown arch
# 20 = 'uname' not found in path
#-------------------------------------------------------------------------------
determine_arch() {
local uname_out
if command -v uname >/dev/null 2>&1; then
uname_out="$(uname -m)"
if [[ "${uname_out}" == "" ]]; then
return 1
else
echo "${uname_out}"
return 0
fi
else
return 20
fi
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: download_file
# DESCRIPTION: Downloads a file into the specified directory. Attempts to
# use curl, then wget. If neither is found, fail.
# PARAMETERS: $1 = url of file to download
# $2 = location to download file into on host system
# RETURNS: If curl or wget found, returns the return code of curl or wget
# 20 = Could not find curl and wget
#-------------------------------------------------------------------------------
download_file() {
local url
local dir
local filename
local rcode
url="${1}"
dir="${2}"
filename="${3}"
if command -v curl >/dev/null 2>&1; then
curl -fsSL "${url}" -o "${dir}/${filename}"
rcode="${?}"
elif command -v wget >/dev/null 2>&1; then
wget --quiet "${url}" -O "${dir}/${filename}"
rcode="${?}"
else
rcode="20"
fi
return "${rcode}"
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: checksum_check
# DESCRIPTION: Attempt to verify checksum of downloaded file to ensure
# integrity. Tries multiple tools before failing.
# PARAMETERS: $1 = path to checksum file
# $2 = location of file to check
# $3 = working directory
# RETURNS: 0 = checkusm verified
# 1 = checksum verification failed
# 20 = failed to determine tool to use to check checksum
# 30 = failed to change into or go back from working dir
#-------------------------------------------------------------------------------
checksum_check() {
local checksum_file
local file
local dir
local rcode
local shasum_1
local shasum_2
local shasum_c
checksum_file="${1}"
file="${2}"
dir="${3}"
cd "${dir}" || return 30
if command -v sha256sum >/dev/null 2>&1; then
## Not all sha256sum versions seem to have --ignore-missing, so filter the checksum file
## to only include the file we downloaded.
grep "$(basename "${file}")" "${checksum_file}" > filtered_checksum.txt
shasum_c="$(sha256sum -c "filtered_checksum.txt")"
rcode="${?}"
elif command -v shasum >/dev/null 2>&1; then
## With shasum on FreeBSD, we don't get to --ignore-missing, so filter the checksum file
## to only include the file we downloaded.
grep "$(basename "${file}")" "${checksum_file}" > filtered_checksum.txt
shasum_c="$(shasum -a 256 -c "filtered_checksum.txt")"
rcode="${?}"
elif command -v sha256 >/dev/null 2>&1; then
## With sha256 on FreeBSD, we don't get to --ignore-missing, so filter the checksum file
## to only include the file we downloaded.
## Also sha256 -c option seems to fail, so fall back to an if statement
grep "$(basename "${file}")" "${checksum_file}" > filtered_checksum.txt
shasum_1="$(sha256 -q "${file}")"
shasum_2="$(awk '{print $1}' filtered_checksum.txt)"
if [[ "${shasum_1}" == "${shasum_2}" ]]; then
rcode="0"
else
rcode="1"
fi
shasum_c="Expected: ${shasum_1}, Got: ${shasum_2}"
else
return 20
fi
cd - >/dev/null 2>&1 || return 30
if [[ "${rcode}" -gt "0" ]]; then
echo "${shasum_c}"
fi
return "${rcode}"
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: extract_file
# DESCRIPTION: Extracts a file into a location. Attempts to determine which
# tool to use by checking file extension.
# PARAMETERS: $1 = file to extract
# $2 = location to extract file into
# $3 = extension
# RETURNS: Return code of the tool used to extract the file
# 20 = Failed to determine which tool to use
# 30 = Failed to find tool in path
#-------------------------------------------------------------------------------
extract_file() {
local file
local dir
local ext
local rcode
file="${1}"
dir="${2}"
ext="${3}"
case "${ext}" in
"zip" ) if command -v unzip >/dev/null 2>&1; then
unzip "${file}" -d "${dir}"
rcode="${?}"
else
rcode="30"
fi
;;
"tar.gz" ) if command -v tar >/dev/null 2>&1; then
tar -xf "${file}" -C "${dir}"
rcode="${?}"
else
rcode="31"
fi
;;
* ) rcode="20";;
esac
return "${rcode}"
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: create_prefix
# DESCRIPTION: Creates the install prefix (and any parent directories). If
# EUID not 0, then attempt to use sudo.
# PARAMETERS: $1 = prefix
# RETURNS: Return code of the tool used to make the directory
# 0 = Created the directory
# >0 = Failed to create directory
# 20 = Could not find mkdir command
# 21 = Could not find sudo command
#-------------------------------------------------------------------------------
create_prefix() {
local prefix
local rcode
prefix="${1}"
if command -v mkdir >/dev/null 2>&1; then
if [[ "${EUID}" == "0" ]]; then
mkdir -p "${prefix}"
rcode="${?}"
else
if command -v sudo >/dev/null 2>&1; then
sudo mkdir -p "${prefix}"
rcode="${?}"
else
rcode="21"
fi
fi
else
rcode="20"
fi
return "${rcode}"
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: install_file_freebsd
# DESCRIPTION: Installs a file into a location using 'install'. If EUID not
# 0, then attempt to use sudo.
# PARAMETERS: $1 = file to install
# $2 = location to install file into
# RETURNS: 0 = File Installed
# 1 = File not installed
# 20 = Could not find install command
# 21 = Could not find sudo command
#-------------------------------------------------------------------------------
install_file_freebsd() {
local file
local prefix
local rcode
file="${1}"
prefix="${2}"
if command -v install >/dev/null 2>&1; then
if [[ "${EUID}" == "0" ]]; then
install -C -b -B '_old' -m 755 "${file}" "${prefix}"
rcode="${?}"
else
if command -v sudo >/dev/null 2>&1; then
sudo install -C -b -B '_old' -m 755 "${file}" "${prefix}"
rcode="${?}"
else
rcode="21"
fi
fi
else
rcode="20"
fi
return "${rcode}"
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: install_file_linux
# DESCRIPTION: Installs a file into a location using 'install'. If EUID not
# 0, then attempt to use sudo (unless on android).
# PARAMETERS: $1 = file to install
# $2 = location to install file into
# RETURNS: 0 = File Installed
# 1 = File not installed
# 20 = Could not find install command
# 21 = Could not find sudo command
#-------------------------------------------------------------------------------
install_file_linux() {
local file
local prefix
local rcode
file="${1}"
prefix="${2}"
if command -v install >/dev/null 2>&1; then
if [[ "${EUID}" == "0" ]]; then
install -C -b -S '_old' -m 755 -t "${prefix}" "${file}"
rcode="${?}"
else
if command -v sudo >/dev/null 2>&1; then
sudo install -C -b -S '_old' -m 755 "${file}" "${prefix}"
rcode="${?}"
elif [[ "${ANDROID_ROOT}" != "" ]]; then
install -C -b -S '_old' -m 755 -t "${prefix}" "${file}"
rcode="${?}"
else
rcode="21"
fi
fi
else
rcode="20"
fi
return "${rcode}"
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: install_file_cygwin
# DESCRIPTION: Installs a file into a location using 'install'. If EUID not
# 0, then attempt to use sudo.
# Not really 100% sure this is how to install croc in cygwin.
# PARAMETERS: $1 = file to install
# $2 = location to install file into
# RETURNS: 0 = File Installed
# 20 = Could not find install command
# 21 = Could not find sudo command
#-------------------------------------------------------------------------------
install_file_cygwin() {
local file
local prefix
local rcode
file="${1}"
prefix="${2}"
if command -v install >/dev/null 2>&1; then
if [[ "${EUID}" == "0" ]]; then
install -m 755 "${prefix}" "${file}"
rcode="${?}"
else
if command -v sudo >/dev/null 2>&1; then
sudo install -m 755 "${file}" "${prefix}"
rcode="${?}"
else
rcode="21"
fi
fi
else
rcode="20"
fi
return "${rcode}"
}
#--- FUNCTION ----------------------------------------------------------------
# NAME: main
# DESCRIPTION: Put it all together in a logical way
# ...at least that is the hope...
# PARAMETERS: 1 = prefix
# RETURNS: 0 = All good
# 1 = Something done broke
#-------------------------------------------------------------------------------
main() {
local prefix
local tmpdir
local tmpdir_rcode
local croc_arch
local croc_arch_rcode
local croc_os
local croc_os_rcode
local croc_base_url
local croc_url
local croc_file
local croc_checksum_file
local croc_bin_name
local croc_version
local croc_dl_ext
local download_file_rcode
local download_checksum_file_rcode
local checksum_check_rcode
local extract_file_rcode
local install_file_rcode
local create_prefix_rcode
local bash_autocomplete_file
local bash_autocomplete_prefix
local zsh_autocomplete_file
local zsh_autocomplete_prefix
local autocomplete_install_rcode
croc_bin_name="croc"
croc_version="10.0.7"
croc_dl_ext="tar.gz"
croc_base_url="https://github.com/schollz/croc/releases/download"
prefix="${1}"
bash_autocomplete_file="bash_autocomplete"
bash_autocomplete_prefix="/etc/bash_completion.d"
zsh_autocomplete_file="zsh_autocomplete"
zsh_autocomplete_prefix="/etc/zsh"
print_banner
print_message "== Install prefix set to ${prefix}" "info"
tmpdir="$(make_tempdir "${croc_bin_name}")"
tmpdir_rcode="${?}"
if [[ "${tmpdir_rcode}" == "0" ]]; then
print_message "== Created temp dir at ${tmpdir}" "info"
elif [[ "${tmpdir_rcode}" == "1" ]]; then
print_message "== Failed to create temp dir at ${tmpdir}" "error"
else
print_message "== 'mktemp' not found in path. Is it installed?" "error"
exit 1
fi
croc_arch="$(determine_arch)"
croc_arch_rcode="${?}"
if [[ "${croc_arch_rcode}" == "0" ]]; then
print_message "== Architecture detected as ${croc_arch}" "info"
elif [[ "${croc_arch_rcode}" == "1" ]]; then
print_message "== Architecture not detected" "error"
exit 1
else
print_message "== 'uname' not found in path. Is it installed?" "error"
exit 1
fi
croc_os="$(determine_os)"
croc_os_rcode="${?}"
if [[ "${croc_os_rcode}" == "0" ]]; then
print_message "== OS detected as ${croc_os}" "info"
elif [[ "${croc_os_rcode}" == "1" ]]; then
print_message "== OS not detected" "error"
exit 1
else
print_message "== 'uname' not found in path. Is it installed?" "error"
exit 1
fi
case "${croc_os}" in
"Darwin" ) croc_os="macOS";;
"CYGWIN"* ) croc_os="Windows";
croc_dl_ext="zip";
print_message "== Cygwin is currently unsupported." "error";
exit 1;;
esac
case "${croc_arch}" in
"x86_64" ) croc_arch="64bit";;
"amd64" ) croc_arch="64bit";;
"aarch64" ) croc_arch="ARM64";;
"arm64" ) croc_arch="ARM64";;
"armv7l" ) croc_arch="ARM";;
"i686" ) croc_arch="32bit";;
* ) croc_arch="unknown";;
esac
croc_file="${croc_bin_name}_v${croc_version}_${croc_os}-${croc_arch}.${croc_dl_ext}"
croc_checksum_file="${croc_bin_name}_v${croc_version}_checksums.txt"
croc_url="${croc_base_url}/v${croc_version}/${croc_file}"
croc_checksum_url="${croc_base_url}/v${croc_version}/${croc_checksum_file}"
echo "${croc_url}" "${tmpdir}" "${croc_file}"
download_file "${croc_url}" "${tmpdir}" "${croc_file}"
download_file_rcode="${?}"
if [[ "${download_file_rcode}" == "0" ]]; then
print_message "== Downloaded croc archive into ${tmpdir}" "info"
elif [[ "${download_file_rcode}" == "1" ]]; then
print_message "== Failed to download croc archive" "error"
exit 1
elif [[ "${download_file_rcode}" == "20" ]]; then
print_message "== Failed to locate curl or wget" "error"
exit 1
else
print_message "== Return code of download tool returned an unexpected value of ${download_file_rcode}" "error"
exit 1
fi
download_file "${croc_checksum_url}" "${tmpdir}" "${croc_checksum_file}"
download_checksum_file_rcode="${?}"
if [[ "${download_checksum_file_rcode}" == "0" ]]; then
print_message "== Downloaded croc checksums file into ${tmpdir}" "info"
elif [[ "${download_checksum_file_rcode}" == "1" ]]; then
print_message "== Failed to download croc checksums" "error"
exit 1
elif [[ "${download_checksum_file_rcode}" == "20" ]]; then
print_message "== Failed to locate curl or wget" "error"
exit 1
else
print_message "== Return code of download tool returned an unexpected value of ${download_checksum_file_rcode}" "error"
exit 1
fi
checksum_check "${tmpdir}/${croc_checksum_file}" "${tmpdir}/${croc_file}" "${tmpdir}"
checksum_check_rcode="${?}"
if [[ "${checksum_check_rcode}" == "0" ]]; then
print_message "== Checksum of ${tmpdir}/${croc_file} verified" "ok"
elif [[ "${checksum_check_rcode}" == "1" ]]; then
print_message "== Failed to verify checksum of ${tmpdir}/${croc_file}" "error"
exit 1
elif [[ "${checksum_check_rcode}" == "20" ]]; then
print_message "== Failed to find tool to verify sha256 sums" "error"
exit 1
elif [[ "${checksum_check_rcode}" == "30" ]]; then
print_message "== Failed to change into working directory ${tmpdir}" "error"
exit 1
else
print_message "== Unknown return code returned while checking checksum of ${tmpdir}/${croc_file}. Returned ${checksum_check_rcode}" "error"
exit 1
fi
extract_file "${tmpdir}/${croc_file}" "${tmpdir}/" "${croc_dl_ext}"
extract_file_rcode="${?}"
if [[ "${extract_file_rcode}" == "0" ]]; then
print_message "== Extracted ${croc_file} to ${tmpdir}/" "info"
elif [[ "${extract_file_rcode}" == "1" ]]; then
print_message "== Failed to extract ${croc_file}" "error"
exit 1
elif [[ "${extract_file_rcode}" == "20" ]]; then
print_message "== Failed to determine which extraction tool to use" "error"
exit 1
elif [[ "${extract_file_rcode}" == "30" ]]; then
print_message "== Failed to find 'unzip' in path" "error"
exit 1
elif [[ "${extract_file_rcode}" == "31" ]]; then
print_message "== Failed to find 'tar' in path" "error"
exit 1
else
print_message "== Unknown error returned from extraction attempt" "error"
exit 1
fi
if [[ ! -d "${prefix}" ]]; then
create_prefix "${prefix}"
create_prefix_rcode="${?}"
if [[ "${create_prefix_rcode}" == "0" ]]; then
print_message "== Created install prefix at ${prefix}" "info"
elif [[ "${create_prefix_rcode}" == "20" ]]; then
print_message "== Failed to find mkdir in path" "error"
exit 1
elif [[ "${create_prefix_rcode}" == "21" ]]; then
print_message "== Failed to find sudo in path" "error"
exit 1
else
print_message "== Failed to create the install prefix: ${prefix}" "error"
exit 1
fi
else
print_message "== Install prefix already exists. No need to create it." "info"
fi
[ ! -d "/etc/bash_completion.d/croc" ] && mkdir -p "/etc/bash_completion.d/croc"
case "${croc_os}" in
"Linux" ) install_file_linux "${tmpdir}/${croc_bin_name}" "${prefix}/";
install_file_rcode="${?}";;
"FreeBSD" ) install_file_freebsd "${tmpdir}/${croc_bin_name}" "${prefix}/";
install_file_rcode="${?}";;
"macOS" ) install_file_freebsd "${tmpdir}/${croc_bin_name}" "${prefix}/";
install_file_rcode="${?}";;
"Windows" ) install_file_cygwin "${tmpdir}/${croc_bin_name}" "${prefix}/";
install_file_rcode="${?}";;
esac
if [[ "${install_file_rcode}" == "0" ]] ; then
print_message "== Installed ${croc_bin_name} to ${prefix}/" "ok"
elif [[ "${install_file_rcode}" == "1" ]]; then
print_message "== Failed to install ${croc_bin_name}" "error"
exit 1
elif [[ "${install_file_rcode}" == "20" ]]; then
print_message "== Failed to locate 'install' command" "error"
exit 1
elif [[ "${install_file_rcode}" == "21" ]]; then
print_message "== Failed to locate 'sudo' command" "error"
exit 1
else
print_message "== Install attempt returned an unexpected value of ${install_file_rcode}" "error"
exit 1
fi
# case "$(basename ${SHELL})" in
# "bash" ) install_file_linux "${tmpdir}/${bash_autocomplete_file}" "${bash_autocomplete_prefix}/croc";
# autocomplete_install_rcode="${?}";;
# "zsh" ) install_file_linux "${tmpdir}/${zsh_autocomplete_file}" "${zsh_autocomplete_prefix}/zsh_autocomplete_croc";
# autocomplete_install_rcode="${?}";
# print_message "== You will need to add the following to your ~/.zshrc to enable autocompletion" "info";
# print_message "\nPROG=croc\n_CLI_ZSH_AUTOCOMPLETE_HACK=1\nsource /etc/zsh/zsh_autocomplete_croc\n" "info";;
# *) autocomplete_install_rcode="1";;
# esac
# if [[ "${autocomplete_install_rcode}" == "0" ]] ; then
# print_message "== Installed autocompletions for $(basename "${SHELL}")" "ok"
# elif [[ "${autocomplete_install_rcode}" == "1" ]]; then
# print_message "== Failed to install ${bash_autocomplete_file}" "error"
# elif [[ "${autocomplete_install_rcode}" == "20" ]]; then
# print_message "== Failed to locate 'install' command" "error"
# elif [[ "${autocomplete_install_rcode}" == "21" ]]; then
# print_message "== Failed to locate 'sudo' command" "error"
# else
# print_message "== Install attempt returned an unexpected value of ${autocomplete_install_rcode}" "error"
# fi
print_message "== Installation complete" "ok"
exit 0
}
#-------------------------------------------------------------------------------
# ARGUMENT PARSING
#-------------------------------------------------------------------------------
OPTS="hp:"
while getopts "${OPTS}" optchar; do
case "${optchar}" in
'h' ) print_help
exit 0
;;
'p' ) INSTALL_PREFIX="${OPTARG}"
;;
/? ) print_message "Unknown option ${OPTARG}" "warn"
;;
esac
done
#-------------------------------------------------------------------------------
# CALL MAIN
#-------------------------------------------------------------------------------
main "${INSTALL_PREFIX}"

View File

@ -0,0 +1,7 @@
#!/bin/bash
tmp=$(mktemp -d)
echo $VERSION
git clone -b v${VERSION} --depth 1 https://github.com/schollz/croc $tmp/croc-${VERSION}
(cd $tmp/croc-${VERSION} && go mod tidy && go mod vendor)
(cd $tmp && tar -cvzf croc_${VERSION}_src.tar.gz croc-${VERSION})
mv $tmp/croc_${VERSION}_src.tar.gz dist/

View File

@ -0,0 +1,77 @@
package main
import (
"fmt"
"os"
"os/exec"
"strings"
)
func main() {
err := run()
if err != nil {
fmt.Println(err)
}
}
func run() (err error) {
versionNew := "v" + os.Getenv("VERSION")
versionHash, err := exec.Command("git", "rev-parse", "--short", "HEAD").Output()
if err != nil {
return
}
versionHashNew := strings.TrimSpace(string(versionHash))
fmt.Println(versionNew)
fmt.Println(versionHashNew)
err = replaceInFile("src/cli/cli.go", `Version = "`, `"`, versionNew+"-"+versionHashNew)
if err == nil {
fmt.Printf("updated cli.go to version %s\n", versionNew)
}
err = replaceInFile("README.md", `version-`, `-b`, strings.Split(versionNew, "-")[0])
if err == nil {
fmt.Printf("updated README to version %s\n", strings.Split(versionNew, "-")[0])
}
err = replaceInFile("src/install/default.txt", `croc_version="`, `"`, strings.Split(versionNew, "-")[0][1:])
if err == nil {
fmt.Printf("updated default.txt to version %s\n", strings.Split(versionNew, "-")[0][1:])
}
return
}
func replaceInFile(fname, start, end, replacement string) (err error) {
b, err := os.ReadFile(fname)
if err != nil {
return
}
oldVersion := GetStringInBetween(string(b), start, end)
if oldVersion == "" {
err = fmt.Errorf("nothing")
return
}
newF := strings.Replace(
string(b),
fmt.Sprintf("%s%s%s", start, oldVersion, end),
fmt.Sprintf("%s%s%s", start, replacement, end),
1,
)
err = os.WriteFile(fname, []byte(newF), 0o644)
return
}
// GetStringInBetween Returns empty string if no start string found
func GetStringInBetween(str string, start string, end string) (result string) {
s := strings.Index(str, start)
if s == -1 {
return
}
s += len(start)
e := strings.Index(str[s:], end)
if e == -1 {
return
}
e += s
return str[s:e]
}

View File

@ -0,0 +1,51 @@
#!/bin/bash
VERSION=$(cat ./src/cli/cli.go | grep 'Version = "v' | sed 's/[^0-9.]*\([0-9.]*\).*/\1/')
echo $VERSION
# Check dependencies.
set -e
xargs=$(which gxargs || which xargs)
# Validate settings.
[ "$TRACE" ] && set -x
CONFIG=$@
for line in $CONFIG; do
eval "$line"
done
owner="schollz"
repo="croc"
tag="v${VERSION}"
filename="dist/croc_${VERSION}_src.tar.gz"
# Define variables.
GH_API="https://api.github.com"
GH_REPO="$GH_API/repos/$owner/$repo"
GH_TAGS="$GH_REPO/releases/tags/$tag"
AUTH="Authorization: token $GITHUB_TOKEN"
WGET_ARGS="--content-disposition --auth-no-challenge --no-cookie"
CURL_ARGS="-LJO#"
if [[ "$tag" == 'LATEST' ]]; then
GH_TAGS="$GH_REPO/releases/latest"
fi
# Validate token.
curl -o /dev/null -sH "$AUTH" $GH_REPO || { echo "Error: Invalid repo, token or network issue!"; exit 1; }
# Read asset tags.
response=$(curl -sH "$AUTH" $GH_TAGS)
# Get ID of the asset based on given filename.
eval $(echo "$response" | grep -m 1 "id.:" | grep -w id | tr : = | tr -cd '[[:alnum:]]=')
[ "$id" ] || { echo "Error: Failed to get release id for tag: $tag"; echo "$response" | awk 'length($0)<100' >&2; exit 1; }
# Upload asset
echo "Uploading asset... "
# Construct url
GH_ASSET="https://uploads.github.com/repos/$owner/$repo/releases/$id/assets?name=$(basename $filename)"
curl "$GITHUB_OAUTH_BASIC" --data-binary @"$filename" -H "Authorization: token $GITHUB_TOKEN" -H "Content-Type: application/octet-stream" $GH_ASSET

View File

@ -0,0 +1,23 @@
#compdef $PROG
_cli_zsh_autocomplete() {
local -a opts
local cur
cur=${words[-1]}
if [[ "$cur" == "-"* ]]; then
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
else
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
fi
if [[ "${opts[1]}" != "" ]]; then
_describe 'values' opts
else
_files
fi
return
}
compdef _cli_zsh_autocomplete $PROG

84
src/message/message.go Normal file
View File

@ -0,0 +1,84 @@
package message
import (
"encoding/json"
"github.com/schollz/croc/v10/src/comm"
"github.com/schollz/croc/v10/src/compress"
"github.com/schollz/croc/v10/src/crypt"
log "github.com/schollz/logger"
)
// Type is a message type
type Type string
const (
TypePAKE Type = "pake"
TypeExternalIP Type = "externalip"
TypeFinished Type = "finished"
TypeError Type = "error"
TypeCloseRecipient Type = "close-recipient"
TypeCloseSender Type = "close-sender"
TypeRecipientReady Type = "recipientready"
TypeFileInfo Type = "fileinfo"
)
// Message is the possible payload for messaging
type Message struct {
Type Type `json:"t,omitempty"`
Message string `json:"m,omitempty"`
Bytes []byte `json:"b,omitempty"`
Bytes2 []byte `json:"b2,omitempty"`
Num int `json:"n,omitempty"`
}
func (m Message) String() string {
b, _ := json.Marshal(m)
return string(b)
}
// Send will send out
func Send(c *comm.Comm, key []byte, m Message) (err error) {
mSend, err := Encode(key, m)
if err != nil {
return
}
err = c.Send(mSend)
return
}
// Encode will convert to bytes
func Encode(key []byte, m Message) (b []byte, err error) {
b, err = json.Marshal(m)
if err != nil {
return
}
b = compress.Compress(b)
if key != nil {
log.Debugf("writing %s message (encrypted)", m.Type)
b, err = crypt.Encrypt(b, key)
} else {
log.Debugf("writing %s message (unencrypted)", m.Type)
}
return
}
// Decode will convert from bytes
func Decode(key []byte, b []byte) (m Message, err error) {
if key != nil {
b, err = crypt.Decrypt(b, key)
if err != nil {
return
}
}
b = compress.Decompress(b)
err = json.Unmarshal(b, &m)
if err == nil {
if key != nil {
log.Debugf("read %s message (encrypted)", m.Type)
} else {
log.Debugf("read %s message (unencrypted)", m.Type)
}
}
return
}

View File

@ -0,0 +1,96 @@
package message
import (
"crypto/rand"
"fmt"
"net"
"testing"
"time"
"github.com/schollz/croc/v10/src/comm"
"github.com/schollz/croc/v10/src/crypt"
log "github.com/schollz/logger"
"github.com/stretchr/testify/assert"
)
var TypeMessage Type = "message"
func TestMessage(t *testing.T) {
log.SetLevel("debug")
m := Message{Type: TypeMessage, Message: "hello, world"}
e, salt, err := crypt.New([]byte("pass"), nil)
assert.Nil(t, err)
fmt.Println(string(salt))
b, err := Encode(e, m)
assert.Nil(t, err)
fmt.Printf("%x\n", b)
m2, err := Decode(e, b)
assert.Nil(t, err)
assert.Equal(t, m, m2)
assert.Equal(t, `{"t":"message","m":"hello, world"}`, m.String())
_, err = Decode([]byte("not pass"), b)
assert.NotNil(t, err)
_, err = Encode([]byte("0"), m)
assert.NotNil(t, err)
}
func TestMessageNoPass(t *testing.T) {
log.SetLevel("debug")
m := Message{Type: TypeMessage, Message: "hello, world"}
b, err := Encode(nil, m)
assert.Nil(t, err)
fmt.Printf("%x\n", b)
m2, err := Decode(nil, b)
assert.Nil(t, err)
assert.Equal(t, m, m2)
assert.Equal(t, `{"t":"message","m":"hello, world"}`, m.String())
}
func TestSend(t *testing.T) {
token := make([]byte, 40000000)
rand.Read(token)
port := "8801"
go func() {
log.Debugf("starting TCP server on " + port)
server, err := net.Listen("tcp", "0.0.0.0:"+port)
if err != nil {
log.Error(err)
}
defer server.Close()
// spawn a new goroutine whenever a client connects
for {
connection, err := server.Accept()
if err != nil {
log.Error(err)
}
log.Debugf("client %s connected", connection.RemoteAddr().String())
go func(_ string, connection net.Conn) {
c := comm.New(connection)
err = c.Send([]byte("hello, world"))
assert.Nil(t, err)
data, err := c.Receive()
assert.Nil(t, err)
assert.Equal(t, []byte("hello, computer"), data)
data, err = c.Receive()
assert.Nil(t, err)
assert.Equal(t, []byte{'\x00'}, data)
data, err = c.Receive()
assert.Nil(t, err)
assert.Equal(t, token, data)
}(port, connection)
}
}()
time.Sleep(800 * time.Millisecond)
a, err := comm.NewConnection("127.0.0.1:"+port, 10*time.Minute)
assert.Nil(t, err)
m := Message{Type: TypeMessage, Message: "hello, world"}
e, salt, err := crypt.New([]byte("pass"), nil)
log.Debug(salt)
assert.Nil(t, err)
assert.Nil(t, Send(a, e, m))
}

149
src/models/constants.go Normal file
View File

@ -0,0 +1,149 @@
package models
import (
"context"
"fmt"
"net"
"os"
"path"
"github.com/schollz/croc/v10/src/utils"
)
// TCP_BUFFER_SIZE is the maximum packet size
const TCP_BUFFER_SIZE = 1024 * 64
// DEFAULT_RELAY is the default relay used (can be set using --relay)
var (
DEFAULT_RELAY = "croc.schollz.com"
DEFAULT_RELAY6 = "croc6.schollz.com"
DEFAULT_PORT = "9009"
DEFAULT_PASSPHRASE = "pass123"
INTERNAL_DNS = false
)
// publicDNS are servers to be queried if a local lookup fails
var publicDNS = []string{
"1.0.0.1", // Cloudflare
"1.1.1.1", // Cloudflare
"[2606:4700:4700::1111]", // Cloudflare
"[2606:4700:4700::1001]", // Cloudflare
"8.8.4.4", // Google
"8.8.8.8", // Google
"[2001:4860:4860::8844]", // Google
"[2001:4860:4860::8888]", // Google
"9.9.9.9", // Quad9
"149.112.112.112", // Quad9
"[2620:fe::fe]", // Quad9
"[2620:fe::fe:9]", // Quad9
"8.26.56.26", // Comodo
"8.20.247.20", // Comodo
"208.67.220.220", // Cisco OpenDNS
"208.67.222.222", // Cisco OpenDNS
"[2620:119:35::35]", // Cisco OpenDNS
"[2620:119:53::53]", // Cisco OpenDNS
}
func getConfigFile(requireValidPath bool) (fname string, err error) {
configFile, err := utils.GetConfigDir(requireValidPath)
if err != nil {
return
}
fname = path.Join(configFile, "internal-dns")
return
}
func init() {
doRemember := false
for _, flag := range os.Args {
if flag == "--internal-dns" {
INTERNAL_DNS = true
break
}
if flag == "--remember" {
doRemember = true
}
}
if doRemember {
// save in config file
fname, err := getConfigFile(true)
if err == nil {
f, _ := os.Create(fname)
f.Close()
}
}
if !INTERNAL_DNS {
fname, err := getConfigFile(false)
if err == nil {
INTERNAL_DNS = utils.Exists(fname)
}
}
var err error
var addr string
addr, err = lookup(DEFAULT_RELAY)
if err == nil {
DEFAULT_RELAY = net.JoinHostPort(addr, DEFAULT_PORT)
} else {
DEFAULT_RELAY = ""
}
addr, err = lookup(DEFAULT_RELAY6)
if err == nil {
DEFAULT_RELAY6 = net.JoinHostPort(addr, DEFAULT_PORT)
} else {
DEFAULT_RELAY6 = ""
}
}
// Resolve a hostname to an IP address using DNS.
func lookup(address string) (ipaddress string, err error) {
if !INTERNAL_DNS {
return localLookupIP(address)
}
type Result struct {
s string
err error
}
result := make(chan Result, len(publicDNS))
for _, dns := range publicDNS {
go func(dns string) {
var r Result
r.s, r.err = remoteLookupIP(address, dns)
result <- r
}(dns)
}
for i := 0; i < len(publicDNS); i++ {
ipaddress = (<-result).s
if ipaddress != "" {
return
}
}
err = fmt.Errorf("failed to resolve %s: all DNS servers exhausted", address)
return
}
// localLookupIP returns a host's IP address based on the local resolver.
func localLookupIP(address string) (ipaddress string, err error) {
ip, err := net.LookupHost(address)
if err != nil {
return
}
ipaddress = ip[0]
return
}
// remoteLookupIP returns a host's IP address based on a remote DNS server.
func remoteLookupIP(address, dns string) (ipaddress string, err error) {
r := &net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, _ string) (net.Conn, error) {
d := new(net.Dialer)
return d.DialContext(ctx, network, dns+":53")
},
}
ip, err := r.LookupHost(context.Background(), address)
if err != nil {
return
}
ipaddress = ip[0]
return
}

548
src/tcp/tcp.go Normal file
View File

@ -0,0 +1,548 @@
package tcp
import (
"bytes"
"fmt"
"net"
"strings"
"sync"
"time"
log "github.com/schollz/logger"
"github.com/schollz/pake/v3"
"github.com/schollz/croc/v10/src/comm"
"github.com/schollz/croc/v10/src/crypt"
"github.com/schollz/croc/v10/src/models"
)
type server struct {
host string
port string
debugLevel string
banner string
password string
rooms roomMap
}
type roomInfo struct {
first *comm.Comm
second *comm.Comm
opened time.Time
full bool
}
type roomMap struct {
rooms map[string]roomInfo
sync.Mutex
}
const pingRoom = "pinglkasjdlfjsaldjf"
var timeToRoomDeletion = 10 * time.Minute
// Run starts a tcp listener, run async
func Run(debugLevel, host, port, password string, banner ...string) (err error) {
s := new(server)
s.host = host
s.port = port
s.password = password
s.debugLevel = debugLevel
if len(banner) > 0 {
s.banner = banner[0]
}
return s.start()
}
func (s *server) start() (err error) {
log.SetLevel(s.debugLevel)
log.Debugf("starting with password '%s'", s.password)
s.rooms.Lock()
s.rooms.rooms = make(map[string]roomInfo)
s.rooms.Unlock()
// delete old rooms
go func() {
for {
time.Sleep(timeToRoomDeletion)
var roomsToDelete []string
s.rooms.Lock()
for room := range s.rooms.rooms {
if time.Since(s.rooms.rooms[room].opened) > 3*time.Hour {
roomsToDelete = append(roomsToDelete, room)
}
}
s.rooms.Unlock()
for _, room := range roomsToDelete {
s.deleteRoom(room)
}
}
}()
err = s.run()
if err != nil {
log.Error(err)
}
return
}
func (s *server) run() (err error) {
network := "tcp"
addr := net.JoinHostPort(s.host, s.port)
if s.host != "" {
ip := net.ParseIP(s.host)
if ip == nil {
var tcpIP *net.IPAddr
tcpIP, err = net.ResolveIPAddr("ip", s.host)
if err != nil {
return err
}
ip = tcpIP.IP
}
addr = net.JoinHostPort(ip.String(), s.port)
if s.host != "" {
if ip.To4() != nil {
network = "tcp4"
} else {
network = "tcp6"
}
}
}
addr = strings.Replace(addr, "127.0.0.1", "0.0.0.0", 1)
log.Infof("starting TCP server on " + addr)
server, err := net.Listen(network, addr)
if err != nil {
return fmt.Errorf("error listening on %s: %w", addr, err)
}
defer server.Close()
// spawn a new goroutine whenever a client connects
for {
connection, err := server.Accept()
if err != nil {
return fmt.Errorf("problem accepting connection: %w", err)
}
log.Debugf("client %s connected", connection.RemoteAddr().String())
go func(port string, connection net.Conn) {
c := comm.New(connection)
room, errCommunication := s.clientCommunication(port, c)
log.Debugf("room: %+v", room)
log.Debugf("err: %+v", errCommunication)
if errCommunication != nil {
log.Debugf("relay-%s: %s", connection.RemoteAddr().String(), errCommunication.Error())
connection.Close()
return
}
if room == pingRoom {
log.Debugf("got ping")
connection.Close()
return
}
for {
// check connection
log.Debugf("checking connection of room %s for %+v", room, c)
deleteIt := false
s.rooms.Lock()
if _, ok := s.rooms.rooms[room]; !ok {
log.Debug("room is gone")
s.rooms.Unlock()
return
}
log.Debugf("room: %+v", s.rooms.rooms[room])
if s.rooms.rooms[room].first != nil && s.rooms.rooms[room].second != nil {
log.Debug("rooms ready")
s.rooms.Unlock()
break
} else {
if s.rooms.rooms[room].first != nil {
errSend := s.rooms.rooms[room].first.Send([]byte{1})
if errSend != nil {
log.Debug(errSend)
deleteIt = true
}
}
}
s.rooms.Unlock()
if deleteIt {
s.deleteRoom(room)
break
}
time.Sleep(1 * time.Second)
}
}(s.port, connection)
}
}
var weakKey = []byte{1, 2, 3}
func (s *server) clientCommunication(port string, c *comm.Comm) (room string, err error) {
// establish secure password with PAKE for communication with relay
B, err := pake.InitCurve(weakKey, 1, "siec")
if err != nil {
return
}
Abytes, err := c.Receive()
if err != nil {
return
}
log.Debugf("Abytes: %s", Abytes)
if bytes.Equal(Abytes, []byte("ping")) {
room = pingRoom
log.Debug("sending back pong")
c.Send([]byte("pong"))
return
}
err = B.Update(Abytes)
if err != nil {
return
}
err = c.Send(B.Bytes())
if err != nil {
return
}
strongKey, err := B.SessionKey()
if err != nil {
return
}
log.Debugf("strongkey: %x", strongKey)
// receive salt
salt, err := c.Receive()
if err != nil {
return
}
strongKeyForEncryption, _, err := crypt.New(strongKey, salt)
if err != nil {
return
}
log.Debugf("waiting for password")
passwordBytesEnc, err := c.Receive()
if err != nil {
return
}
passwordBytes, err := crypt.Decrypt(passwordBytesEnc, strongKeyForEncryption)
if err != nil {
return
}
if strings.TrimSpace(string(passwordBytes)) != s.password {
err = fmt.Errorf("bad password")
enc, _ := crypt.Encrypt([]byte(err.Error()), strongKeyForEncryption)
if err = c.Send(enc); err != nil {
return "", fmt.Errorf("send error: %w", err)
}
return
}
// send ok to tell client they are connected
banner := s.banner
if len(banner) == 0 {
banner = "ok"
}
log.Debugf("sending '%s'", banner)
bSend, err := crypt.Encrypt([]byte(banner+"|||"+c.Connection().RemoteAddr().String()), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
if err != nil {
return
}
// wait for client to tell me which room they want
log.Debug("waiting for answer")
enc, err := c.Receive()
if err != nil {
return
}
roomBytes, err := crypt.Decrypt(enc, strongKeyForEncryption)
if err != nil {
return
}
room = string(roomBytes)
s.rooms.Lock()
// create the room if it is new
if _, ok := s.rooms.rooms[room]; !ok {
s.rooms.rooms[room] = roomInfo{
first: c,
opened: time.Now(),
}
s.rooms.Unlock()
// tell the client that they got the room
bSend, err = crypt.Encrypt([]byte("ok"), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
if err != nil {
log.Error(err)
s.deleteRoom(room)
return
}
log.Debugf("room %s has 1", room)
return
}
if s.rooms.rooms[room].full {
s.rooms.Unlock()
bSend, err = crypt.Encrypt([]byte("room full"), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
if err != nil {
log.Error(err)
return
}
return
}
log.Debugf("room %s has 2", room)
s.rooms.rooms[room] = roomInfo{
first: s.rooms.rooms[room].first,
second: c,
opened: s.rooms.rooms[room].opened,
full: true,
}
otherConnection := s.rooms.rooms[room].first
s.rooms.Unlock()
// second connection is the sender, time to staple connections
var wg sync.WaitGroup
wg.Add(1)
// start piping
go func(com1, com2 *comm.Comm, wg *sync.WaitGroup) {
log.Debug("starting pipes")
pipe(com1.Connection(), com2.Connection())
wg.Done()
log.Debug("done piping")
}(otherConnection, c, &wg)
// tell the sender everything is ready
bSend, err = crypt.Encrypt([]byte("ok"), strongKeyForEncryption)
if err != nil {
return
}
err = c.Send(bSend)
if err != nil {
s.deleteRoom(room)
return
}
wg.Wait()
// delete room
s.deleteRoom(room)
return
}
func (s *server) deleteRoom(room string) {
s.rooms.Lock()
defer s.rooms.Unlock()
if _, ok := s.rooms.rooms[room]; !ok {
return
}
log.Debugf("deleting room: %s", room)
if s.rooms.rooms[room].first != nil {
s.rooms.rooms[room].first.Close()
}
if s.rooms.rooms[room].second != nil {
s.rooms.rooms[room].second.Close()
}
s.rooms.rooms[room] = roomInfo{first: nil, second: nil}
delete(s.rooms.rooms, room)
}
// chanFromConn creates a channel from a Conn object, and sends everything it
//
// Read()s from the socket to the channel.
func chanFromConn(conn net.Conn) chan []byte {
c := make(chan []byte, 1)
if err := conn.SetReadDeadline(time.Now().Add(3 * time.Hour)); err != nil {
log.Warnf("can't set read deadline: %v", err)
}
go func() {
b := make([]byte, models.TCP_BUFFER_SIZE)
for {
n, err := conn.Read(b)
if n > 0 {
res := make([]byte, n)
// Copy the buffer so it doesn't get changed while read by the recipient.
copy(res, b[:n])
c <- res
}
if err != nil {
log.Debug(err)
c <- nil
break
}
}
log.Debug("exiting")
}()
return c
}
// pipe creates a full-duplex pipe between the two sockets and
// transfers data from one to the other.
func pipe(conn1 net.Conn, conn2 net.Conn) {
chan1 := chanFromConn(conn1)
chan2 := chanFromConn(conn2)
for {
select {
case b1 := <-chan1:
if b1 == nil {
return
}
if _, err := conn2.Write(b1); err != nil {
log.Errorf("write error on channel 1: %v", err)
}
case b2 := <-chan2:
if b2 == nil {
return
}
if _, err := conn1.Write(b2); err != nil {
log.Errorf("write error on channel 2: %v", err)
}
}
}
}
func PingServer(address string) (err error) {
log.Debugf("pinging %s", address)
c, err := comm.NewConnection(address, 300*time.Millisecond)
if err != nil {
log.Debug(err)
return
}
err = c.Send([]byte("ping"))
if err != nil {
log.Debug(err)
return
}
b, err := c.Receive()
if err != nil {
log.Debug(err)
return
}
if bytes.Equal(b, []byte("pong")) {
return nil
}
return fmt.Errorf("no pong")
}
// ConnectToTCPServer will initiate a new connection
// to the specified address, room with optional time limit
func ConnectToTCPServer(address, password, room string, timelimit ...time.Duration) (c *comm.Comm, banner string, ipaddr string, err error) {
if len(timelimit) > 0 {
c, err = comm.NewConnection(address, timelimit[0])
} else {
c, err = comm.NewConnection(address)
}
if err != nil {
log.Debug(err)
return
}
// get PAKE connection with server to establish strong key to transfer info
A, err := pake.InitCurve(weakKey, 0, "siec")
if err != nil {
log.Debug(err)
return
}
err = c.Send(A.Bytes())
if err != nil {
log.Debug(err)
return
}
Bbytes, err := c.Receive()
if err != nil {
log.Debug(err)
return
}
err = A.Update(Bbytes)
if err != nil {
log.Debug(err)
return
}
strongKey, err := A.SessionKey()
if err != nil {
log.Debug(err)
return
}
log.Debugf("strong key: %x", strongKey)
strongKeyForEncryption, salt, err := crypt.New(strongKey, nil)
if err != nil {
log.Debug(err)
return
}
// send salt
err = c.Send(salt)
if err != nil {
log.Debug(err)
return
}
log.Debug("sending password")
bSend, err := crypt.Encrypt([]byte(password), strongKeyForEncryption)
if err != nil {
log.Debug(err)
return
}
err = c.Send(bSend)
if err != nil {
log.Debug(err)
return
}
log.Debug("waiting for first ok")
enc, err := c.Receive()
if err != nil {
log.Debug(err)
return
}
data, err := crypt.Decrypt(enc, strongKeyForEncryption)
if err != nil {
log.Debug(err)
return
}
if !strings.Contains(string(data), "|||") {
err = fmt.Errorf("bad response: %s", string(data))
log.Debug(err)
return
}
banner = strings.Split(string(data), "|||")[0]
ipaddr = strings.Split(string(data), "|||")[1]
log.Debugf("sending room; %s", room)
bSend, err = crypt.Encrypt([]byte(room), strongKeyForEncryption)
if err != nil {
log.Debug(err)
return
}
err = c.Send(bSend)
if err != nil {
log.Debug(err)
return
}
log.Debug("waiting for room confirmation")
enc, err = c.Receive()
if err != nil {
log.Debug(err)
return
}
data, err = crypt.Decrypt(enc, strongKeyForEncryption)
if err != nil {
log.Debug(err)
return
}
if !bytes.Equal(data, []byte("ok")) {
err = fmt.Errorf("got bad response: %s", data)
log.Debug(err)
return
}
log.Debug("all set")
return
}

71
src/tcp/tcp_test.go Normal file
View File

@ -0,0 +1,71 @@
package tcp
import (
"bytes"
"fmt"
"testing"
"time"
log "github.com/schollz/logger"
"github.com/stretchr/testify/assert"
)
func BenchmarkConnection(b *testing.B) {
log.SetLevel("trace")
go Run("debug", "127.0.0.1", "8283", "pass123", "8284")
time.Sleep(100 * time.Millisecond)
b.ResetTimer()
for i := 0; i < b.N; i++ {
c, _, _, _ := ConnectToTCPServer("127.0.0.1:8283", "pass123", fmt.Sprintf("testroom%d", i), 1*time.Minute)
c.Close()
}
}
func TestTCP(t *testing.T) {
log.SetLevel("error")
timeToRoomDeletion = 100 * time.Millisecond
go Run("debug", "127.0.0.1", "8381", "pass123", "8382")
time.Sleep(timeToRoomDeletion)
err := PingServer("127.0.0.1:8381")
assert.Nil(t, err)
err = PingServer("127.0.0.1:8333")
assert.NotNil(t, err)
time.Sleep(timeToRoomDeletion)
c1, banner, _, err := ConnectToTCPServer("127.0.0.1:8381", "pass123", "testRoom", 1*time.Minute)
assert.Equal(t, banner, "8382")
assert.Nil(t, err)
c2, _, _, err := ConnectToTCPServer("127.0.0.1:8381", "pass123", "testRoom")
assert.Nil(t, err)
_, _, _, err = ConnectToTCPServer("127.0.0.1:8381", "pass123", "testRoom")
assert.NotNil(t, err)
_, _, _, err = ConnectToTCPServer("127.0.0.1:8381", "pass123", "testRoom", 1*time.Nanosecond)
assert.NotNil(t, err)
// try sending data
assert.Nil(t, c1.Send([]byte("hello, c2")))
var data []byte
for {
data, err = c2.Receive()
if bytes.Equal(data, []byte{1}) {
continue
}
break
}
assert.Nil(t, err)
assert.Equal(t, []byte("hello, c2"), data)
assert.Nil(t, c2.Send([]byte("hello, c1")))
for {
data, err = c1.Receive()
if bytes.Equal(data, []byte{1}) {
continue
}
break
}
assert.Nil(t, err)
assert.Equal(t, []byte("hello, c1"), data)
c1.Close()
time.Sleep(300 * time.Millisecond)
}

589
src/utils/utils.go Normal file
View File

@ -0,0 +1,589 @@
package utils
import (
"archive/zip"
"bufio"
"bytes"
"compress/flate"
"crypto/md5"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"log"
"math"
"math/big"
"net"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
"unicode"
"github.com/cespare/xxhash"
"github.com/kalafut/imohash"
"github.com/minio/highwayhash"
"github.com/schollz/mnemonicode"
"github.com/schollz/progressbar/v3"
)
const NbPinNumbers = 4
const NbBytesWords = 4
// Get or create home directory
func GetConfigDir(requireValidPath bool) (homedir string, err error) {
if envHomedir, isSet := os.LookupEnv("CROC_CONFIG_DIR"); isSet {
homedir = envHomedir
} else if xdgConfigHome, isSet := os.LookupEnv("XDG_CONFIG_HOME"); isSet {
homedir = path.Join(xdgConfigHome, "croc")
} else {
homedir, err = os.UserHomeDir()
if err != nil {
if !requireValidPath {
err = nil
homedir = ""
}
return
}
homedir = path.Join(homedir, ".config", "croc")
}
if requireValidPath {
if _, err = os.Stat(homedir); os.IsNotExist(err) {
err = os.MkdirAll(homedir, 0o700)
}
}
return
}
// Exists reports whether the named file or directory exists.
func Exists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
// GetInput returns the input with a given prompt
func GetInput(prompt string) string {
reader := bufio.NewReader(os.Stdin)
fmt.Fprintf(os.Stderr, "%s", prompt)
text, _ := reader.ReadString('\n')
return strings.TrimSpace(text)
}
// 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.
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
fstats, err = os.Lstat(fname)
if err != nil {
return nil, err
}
if fstats.Mode()&os.ModeSymlink != 0 {
var target string
target, err = os.Readlink(fname)
if err != nil {
return nil, err
}
return []byte(SHA256(target)), nil
}
switch algorithm {
case "imohash":
return IMOHashFile(fname)
case "md5":
return MD5HashFile(fname, doShowProgress)
case "xxhash":
return XXHashFile(fname, doShowProgress)
case "highway":
return HighwayHashFile(fname, doShowProgress)
}
err = fmt.Errorf("unspecified algorithm")
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
func MD5HashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
}
defer f.Close()
h := md5.New()
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
}
}
hash256 = h.Sum(nil)
return
}
// IMOHashFile returns imohash
func IMOHashFile(fname string) (hash []byte, err error) {
b, err := imohash.SumFile(fname)
hash = b[:]
return
}
var imofull = imohash.NewCustom(0, 0)
// IMOHashFileFull returns imohash of full file
func IMOHashFileFull(fname string) (hash []byte, err error) {
b, err := imofull.SumFile(fname)
hash = b[:]
return
}
// XXHashFile returns the xxhash of a file
func XXHashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
f, err := os.Open(fname)
if err != nil {
return
}
defer f.Close()
h := xxhash.New()
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
}
}
hash256 = h.Sum(nil)
return
}
// SHA256 returns sha256 sum
func SHA256(s string) string {
sha := sha256.New()
sha.Write([]byte(s))
return hex.EncodeToString(sha.Sum(nil))
}
// PublicIP returns public ip address
func PublicIP() (ip string, err error) {
resp, err := http.Get("https://canhazip.com")
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
ip = strings.TrimSpace(string(bodyBytes))
}
return
}
// LocalIP returns local ip address
func LocalIP() string {
conn, err := net.Dial("udp", "8.8.8.8:80")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP.String()
}
func GenerateRandomPin() string {
s := ""
max := new(big.Int)
max.SetInt64(9)
for i := 0; i < NbPinNumbers; i++ {
v, err := rand.Int(rand.Reader, max)
if err != nil {
panic(err)
}
s += fmt.Sprintf("%d", v)
}
return s
}
// GetRandomName returns mnemonicoded random name
func GetRandomName() string {
var result []string
bs := make([]byte, NbBytesWords)
rand.Read(bs)
result = mnemonicode.EncodeWordList(result, bs)
return GenerateRandomPin() + "-" + strings.Join(result, "-")
}
// ByteCountDecimal converts bytes to human readable byte string
func ByteCountDecimal(b int64) string {
const unit = 1024
if b < unit {
return fmt.Sprintf("%d B", b)
}
div, exp := int64(unit), 0
for n := b / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp])
}
// MissingChunks returns the positions of missing chunks.
// If file doesn't exist, it returns an empty chunk list (all chunks).
// If the file size is not the same as requested, it returns an empty chunk list (all chunks).
func MissingChunks(fname string, fsize int64, chunkSize int) (chunkRanges []int64) {
f, err := os.Open(fname)
if err != nil {
return
}
defer f.Close()
fstat, err := os.Stat(fname)
if err != nil || fstat.Size() != fsize {
return
}
emptyBuffer := make([]byte, chunkSize)
chunkNum := 0
chunks := make([]int64, int64(math.Ceil(float64(fsize)/float64(chunkSize))))
var currentLocation int64
for {
buffer := make([]byte, chunkSize)
bytesread, err := f.Read(buffer)
if err != nil {
break
}
if bytes.Equal(buffer[:bytesread], emptyBuffer[:bytesread]) {
chunks[chunkNum] = currentLocation
chunkNum++
}
currentLocation += int64(bytesread)
}
if chunkNum == 0 {
chunkRanges = []int64{}
} else {
chunks = chunks[:chunkNum]
chunkRanges = []int64{int64(chunkSize), chunks[0]}
curCount := 0
for i, chunk := range chunks {
if i == 0 {
continue
}
curCount++
if chunk-chunks[i-1] > int64(chunkSize) {
chunkRanges = append(chunkRanges, int64(curCount))
chunkRanges = append(chunkRanges, chunk)
curCount = 0
}
}
chunkRanges = append(chunkRanges, int64(curCount+1))
}
return
}
// ChunkRangesToChunks converts chunk ranges to list
func ChunkRangesToChunks(chunkRanges []int64) (chunks []int64) {
if len(chunkRanges) == 0 {
return
}
chunkSize := chunkRanges[0]
chunks = []int64{}
for i := 1; i < len(chunkRanges); i += 2 {
for j := int64(0); j < (chunkRanges[i+1]); j++ {
chunks = append(chunks, chunkRanges[i]+j*chunkSize)
}
}
return
}
// GetLocalIPs returns all local ips
func GetLocalIPs() (ips []string, err error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return
}
ips = []string{}
for _, address := range addrs {
// check the address type and if it is not a loopback the display it
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
ips = append(ips, ipnet.IP.String())
}
}
}
return
}
func RandomFileName() (fname string, err error) {
f, err := os.CreateTemp(".", "croc-stdin-")
if err != nil {
return
}
fname = f.Name()
_ = f.Close()
return
}
func FindOpenPorts(host string, portNumStart, numPorts int) (openPorts []int) {
openPorts = []int{}
for port := portNumStart; port-portNumStart < 200; port++ {
timeout := 100 * time.Millisecond
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, fmt.Sprint(port)), timeout)
if conn != nil {
conn.Close()
} else if err != nil {
openPorts = append(openPorts, port)
}
if len(openPorts) >= numPorts {
return
}
}
return
}
// local ip determination
// https://stackoverflow.com/questions/41240761/check-if-ip-address-is-in-private-network-space
var privateIPBlocks []*net.IPNet
func init() {
for _, cidr := range []string{
"127.0.0.0/8", // IPv4 loopback
"10.0.0.0/8", // RFC1918
"172.16.0.0/12", // RFC1918
"192.168.0.0/16", // RFC1918
"169.254.0.0/16", // RFC3927 link-local
"::1/128", // IPv6 loopback
"fe80::/10", // IPv6 link-local
"fc00::/7", // IPv6 unique local addr
} {
_, block, err := net.ParseCIDR(cidr)
if err != nil {
panic(fmt.Errorf("parse error on %q: %v", cidr, err))
}
privateIPBlocks = append(privateIPBlocks, block)
}
}
func IsLocalIP(ipaddress string) bool {
if strings.Contains(ipaddress, "127.0.0.1") {
return true
}
host, _, _ := net.SplitHostPort(ipaddress)
ip := net.ParseIP(host)
if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() {
return true
}
for _, block := range privateIPBlocks {
if block.Contains(ip) {
return true
}
}
return false
}
func ZipDirectory(destination string, source string) (err error) {
if _, err = os.Stat(destination); err == nil {
log.Fatalf("%s file already exists!\n", destination)
}
fmt.Fprintf(os.Stderr, "Zipping %s to %s\n", source, destination)
file, err := os.Create(destination)
if err != nil {
log.Fatalln(err)
}
defer file.Close()
writer := zip.NewWriter(file)
// no compression because croc does its compression on the fly
writer.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
return flate.NewWriter(out, flate.NoCompression)
})
defer writer.Close()
err = filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
if err != nil {
log.Fatalln(err)
}
if info.Mode().IsRegular() {
f1, err := os.Open(path)
if err != nil {
log.Fatalln(err)
}
defer f1.Close()
zipPath := strings.ReplaceAll(path, source, strings.TrimSuffix(destination, ".zip"))
zipPath = filepath.ToSlash(zipPath)
w1, err := writer.Create(zipPath)
if err != nil {
log.Fatalln(err)
}
if _, err := io.Copy(w1, f1); err != nil {
log.Fatalln(err)
}
fmt.Fprintf(os.Stderr, "\r\033[2K")
fmt.Fprintf(os.Stderr, "\rAdding %s", zipPath)
}
return nil
})
if err != nil {
log.Fatalln(err)
}
fmt.Fprintf(os.Stderr, "\n")
return nil
}
func UnzipDirectory(destination string, source string) error {
archive, err := zip.OpenReader(source)
if err != nil {
log.Fatalln(err)
}
defer archive.Close()
for _, f := range archive.File {
filePath := filepath.Join(destination, f.Name)
fmt.Fprintf(os.Stderr, "\r\033[2K")
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() {
os.MkdirAll(filePath, os.ModePerm)
continue
}
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
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())
if err != nil {
log.Fatalln(err)
}
fileInArchive, err := f.Open()
if err != nil {
log.Fatalln(err)
}
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
log.Fatalln(err)
}
dstFile.Close()
fileInArchive.Close()
}
fmt.Fprintf(os.Stderr, "\n")
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)
}

262
src/utils/utils_test.go Normal file
View File

@ -0,0 +1,262 @@
package utils
import (
"bytes"
"fmt"
"log"
"math/rand"
"os"
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
const TCP_BUFFER_SIZE = 1024 * 64
var bigFileSize = 75000000
func bigFile() {
os.WriteFile("bigfile.test", bytes.Repeat([]byte("z"), bigFileSize), 0o666)
}
func BenchmarkMD5(b *testing.B) {
bigFile()
b.ResetTimer()
for i := 0; i < b.N; i++ {
MD5HashFile("bigfile.test", false)
}
}
func BenchmarkXXHash(b *testing.B) {
bigFile()
b.ResetTimer()
for i := 0; i < b.N; i++ {
XXHashFile("bigfile.test", false)
}
}
func BenchmarkImoHash(b *testing.B) {
bigFile()
b.ResetTimer()
for i := 0; i < b.N; i++ {
IMOHashFile("bigfile.test")
}
}
func BenchmarkHighwayHash(b *testing.B) {
bigFile()
b.ResetTimer()
for i := 0; i < b.N; i++ {
HighwayHashFile("bigfile.test", false)
}
}
func BenchmarkImoHashFull(b *testing.B) {
bigFile()
b.ResetTimer()
for i := 0; i < b.N; i++ {
IMOHashFileFull("bigfile.test")
}
}
func BenchmarkSha256(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
SHA256("hello,world")
}
}
func BenchmarkMissingChunks(b *testing.B) {
bigFile()
b.ResetTimer()
for i := 0; i < b.N; i++ {
MissingChunks("bigfile.test", int64(bigFileSize), TCP_BUFFER_SIZE/2)
}
}
func TestExists(t *testing.T) {
bigFile()
defer os.Remove("bigfile.test")
fmt.Println(GetLocalIPs())
assert.True(t, Exists("bigfile.test"))
assert.False(t, Exists("doesnotexist"))
}
func TestMD5HashFile(t *testing.T) {
bigFile()
defer os.Remove("bigfile.test")
b, err := MD5HashFile("bigfile.test", false)
assert.Nil(t, err)
assert.Equal(t, "8304ff018e02baad0e3555bade29a405", fmt.Sprintf("%x", b))
_, 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)
}
func TestIMOHashFile(t *testing.T) {
bigFile()
defer os.Remove("bigfile.test")
b, err := IMOHashFile("bigfile.test")
assert.Nil(t, err)
assert.Equal(t, "c0d1e123ca94148ffea146137684ebb9", fmt.Sprintf("%x", b))
}
func TestXXHashFile(t *testing.T) {
bigFile()
defer os.Remove("bigfile.test")
b, err := XXHashFile("bigfile.test", false)
assert.Nil(t, err)
assert.Equal(t, "4918740eb5ccb6f7", fmt.Sprintf("%x", b))
_, err = XXHashFile("nofile", false)
assert.NotNil(t, err)
}
func TestSHA256(t *testing.T) {
assert.Equal(t, "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b", SHA256("hello, world"))
}
func TestByteCountDecimal(t *testing.T) {
assert.Equal(t, "10.0 kB", ByteCountDecimal(10240))
assert.Equal(t, "50 B", ByteCountDecimal(50))
assert.Equal(t, "12.4 MB", ByteCountDecimal(13002343))
}
func TestMissingChunks(t *testing.T) {
fileSize := 100
chunkSize := 10
rand.Seed(1)
bigBuff := make([]byte, fileSize)
rand.Read(bigBuff)
os.WriteFile("missing.test", bigBuff, 0o644)
empty := make([]byte, chunkSize)
f, err := os.OpenFile("missing.test", os.O_RDWR, 0o644)
assert.Nil(t, err)
for block := 0; block < fileSize/chunkSize; block++ {
if block == 0 || block == 4 || block == 5 || block >= 7 {
f.WriteAt(empty, int64(block*chunkSize))
}
}
f.Close()
chunkRanges := MissingChunks("missing.test", int64(fileSize), chunkSize)
assert.Equal(t, []int64{10, 0, 1, 40, 2, 70, 3}, chunkRanges)
chunks := ChunkRangesToChunks(chunkRanges)
assert.Equal(t, []int64{0, 40, 50, 70, 80, 90}, chunks)
os.Remove("missing.test")
content := []byte("temporary file's content")
tmpfile, err := os.CreateTemp("", "example")
if err != nil {
log.Fatal(err)
}
defer os.Remove(tmpfile.Name()) // clean up
if _, err := tmpfile.Write(content); err != nil {
panic(err)
}
if err := tmpfile.Close(); err != nil {
panic(err)
}
chunkRanges = MissingChunks(tmpfile.Name(), int64(len(content)), chunkSize)
assert.Empty(t, chunkRanges)
chunkRanges = MissingChunks(tmpfile.Name(), int64(len(content)+10), chunkSize)
assert.Empty(t, chunkRanges)
chunkRanges = MissingChunks(tmpfile.Name()+"ok", int64(len(content)), chunkSize)
assert.Empty(t, chunkRanges)
chunks = ChunkRangesToChunks(chunkRanges)
assert.Empty(t, chunks)
}
// func Test1(t *testing.T) {
// chunkRanges := MissingChunks("../../m/bigfile.test", int64(75000000), 1024*64/2)
// fmt.Println(chunkRanges)
// fmt.Println(ChunkRangesToChunks((chunkRanges)))
// assert.Nil(t, nil)
// }
func TestHashFile(t *testing.T) {
content := []byte("temporary file's content")
tmpfile, err := os.CreateTemp("", "example")
if err != nil {
log.Fatal(err)
}
defer os.Remove(tmpfile.Name()) // clean up
if _, err = tmpfile.Write(content); err != nil {
panic(err)
}
if err = tmpfile.Close(); err != nil {
panic(err)
}
hashed, err := HashFile(tmpfile.Name(), "xxhash")
assert.Nil(t, err)
assert.Equal(t, "e66c561610ad51e2", fmt.Sprintf("%x", hashed))
}
func TestPublicIP(t *testing.T) {
ip, err := PublicIP()
fmt.Println(ip)
assert.True(t, strings.Contains(ip, ".") || strings.Contains(ip, ":"))
assert.Nil(t, err)
}
func TestLocalIP(t *testing.T) {
ip := LocalIP()
fmt.Println(ip)
assert.True(t, strings.Contains(ip, ".") || strings.Contains(ip, ":"))
}
func TestGetRandomName(t *testing.T) {
name := GetRandomName()
fmt.Println(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) {
openPorts := FindOpenPorts("127.0.0.1", 9009, 4)
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) {
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"))
}

View File

@ -1,113 +0,0 @@
<p align="center">
<img
src="https://user-images.githubusercontent.com/6550035/31846899-2b8a7034-b5cf-11e7-9643-afe552226c59.png"
width="100%" border="0" alt="croc">
<br>
<a href="https://github.com/schollz/croc/releases/latest"><img src="https://img.shields.io/badge/version-0.1.0-green.svg?style=flat-square" alt="Version"></a>
<a href="https://gitter.im/schollz/croc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge"><img src="https://img.shields.io/badge/chat-on%20gitter-green.svg?style=flat-square" alt="Version"></a>
</p>
<p align="center">Secure transfer of stuff from one side of the internet to the other.</p>
This is more or less (but mostly *less*) a Golang port of [@warner's](https://github.com/warner) [*magic-wormhole*](https://github.com/warner/magic-wormhole) which allows you to directly transfer files and folders between computers. I decided to make this because I wanted to send my friend Jessie a file using *magic-wormhole* and when I told Jessie how to install the dependencies she made this face: :sob:. So, nominally, *croc* does the same thing (encrypted file transfer directly between computers) without dependencies so you can just double-click on your computer, even if you use Windows.
**Don't we have enough open-source peer-to-peer file-transfer utilities?**
[There](https://github.com/cowbell/sharedrop) [are](https://github.com/webtorrent/instant.io) [great](https://github.com/kern/filepizza) [tools](https://github.com/warner/magic-wormhole) [that](https://github.com/zerotier/toss) [already](https://github.com/ipfs/go-ipfs) [do](https://github.com/zerotier/toss) [this](https://github.com/nils-werner/zget). But, no we don't, because after review, [I found it was useful to make a new one](https://schollz.github.io/sending-a-file/).
# Example
_These two gifs should run in sync if you force-reload (Ctl+F5)_
**Sender:**
![send](https://user-images.githubusercontent.com/6550035/31864532-ad80c6ae-b71b-11e7-91f9-bcba8143d3cf.gif)
**Receiver:**
![receive](https://user-images.githubusercontent.com/6550035/31864531-ad6e22c4-b71b-11e7-901a-02a210057cf1.gif)
**Sender:**
```
$ croc -send croc.exe
Sending 4.4 MB file named 'croc.exe'
Code is: 4-cement-galaxy-alpha
Sending (->24.65.41.43:50843)..
0s [==========================================================] 100%
File sent.
```
**Receiver:**
```
$ croc
Enter receive code: 4-cement-galaxy-alpha
Receiving file (4.4 MB) into: croc.exe
ok? (y/n): y
Receiving (<-50.32.38.188:50843)..
0s [==========================================================] 100%
Received file written to croc.exe
```
Note, by default, you don't need any arguments for receiving! This makes it possible for you to just double click the executable to run (nice for those of us that aren't computer wizards).
# Install
[Download the latest release for your system](https://github.com/schollz/croc/releases/latest).
Or, you can [install Go](https://golang.org/dl/) and build from source with `go get github.com/schollz/croc`.
# How does it work?
*croc* is similar to [magic-wormhole](https://github.com/warner/magic-wormhole#design) in spirit and design. Like *magic-wormhole*, *croc* generates a code phrase for you to share with your friend which allows secure end-to-end transfering of files and folders through a intermediary relay that connects the TCP ports between the two computers.
In *croc*, code phrase is 16 random bits that are [menemonic encoded](http://web.archive.org/web/20101031205747/http://www.tothink.com/mnemonic/) plus a prepended integer to specify number of threads. This code phrase is hashed using sha256 and sent to a relay which maps that key to that connection. When the relay finds a matching key for both the receiver and the sender (i.e. they both have the same code phrase), then the sender transmits the encrypted metadata to the receiver through the relay. Then the receiver decrypts and reviews the metadata (file name, size), and chooses whether to consent to the transfer.
After the receiver consents to the transfer, the sender transmits encrypted data through the relay. The relay setups up [Go channels](https://golang.org/doc/effective_go.html?h=chan#channels) for each connection which pipes all the data incoming from that sender's connection out to the receiver's connection. After the transmission the channels are destroyed and all the connection and meta data information is wiped from the relay server. The encrypted file data never is stored on the relay.
**Encryption**
Encryption uses PBKDF2 (see [RFC2898](http://www.ietf.org/rfc/rfc2898.txt)) where the code phrase shared between the sender and receiver is used as the passphrase. For each of the two encrypted data blocks (metadata stored on relay server, and file data transmitted), a random 8-byte salt is used and a IV is generated according to [NIST Recommendation for Block ciphers, Section 8.2](http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf).
**Decryption**
On the receiver's computer, each piece of received encrypted data is written to a separate file. These files are concatenated and then decrypted. The hash of the decrypted file is then checked against the hash transmitted from the sender (part of the meta data block).
## Run your own relay
*croc* relies on a TCP relay to staple the parallel incoming and outgoing connections. The relay temporarily stores connection information and the encrypted meta information. The default uses a public relay at, `cowyo.com`, which has no guarantees except that I guarantee to turn if off as soon as it gets abused ([click here to check the current status of the public relay](https://stats.uptimerobot.com/lOwJYIgRm)).
I recommend you run your own relay, it is very easy. On your server, `your-server.com`, just run
```
$ croc -relay
```
Now, when you use *croc* to send and receive you should add `-server your-server.com` to use your relay server.
_Note:_ If you are behind a firewall, make sure to open up TCP ports 27001-27009.
# Contribute
I am awed by all the [great contributions](#acknowledgements) made! If you feel like contributing, in any way, by all means you can send an Issue, a PR, ask a question, or tweet me ([@yakczar](http://ctt.ec/Rq054)).
# License
MIT
# Acknowledgements
Thanks...
- ...[@warner](https://github.com/warner) for the [idea](https://github.com/warner/magic-wormhole).
- ...[@tscholl2](https://github.com/tscholl2) for the [encryption gists](https://gist.github.com/tscholl2/dc7dc15dc132ea70a98e8542fefffa28).
- ...[@skorokithakis](https://github.com/skorokithakis) for [code on proxying two connections](https://www.stavros.io/posts/proxying-two-connections-go/).
- ...for making pull requests [@Girbons](https://github.com/Girbons), [@techtide](https://github.com/techtide), [@heymatthew](https://github.com/heymatthew), [@Lunsford94](https://github.com/Lunsford94), [@lummie](https://github.com/lummie), [@jesuiscamille](https://github.com/jesuiscamille), [@threefjord](https://github.com/threefjord), [@marcossegovia](https://github.com/marcossegovia), [@csleong98](https://github.com/csleong98), [@afotescu](https://github.com/afotescu)!

View File

@ -1 +0,0 @@
Some simple text to see if it works

View File

@ -1 +0,0 @@
More data to see if it 100% works

172
utils.go
View File

@ -1,172 +0,0 @@
package main
import (
"crypto/md5"
"fmt"
"io"
"math"
"os"
"strconv"
"github.com/pkg/errors"
)
// CatFiles copies data from n files to a single one and removes source files
// if Debug mode is set to false
func CatFiles(files []string, outfile string, remove bool) error {
finished, err := os.Create(outfile)
if err != nil {
return errors.Wrap(err, "CatFiles create: ")
}
defer finished.Close()
for _, file := range files {
fh, err := os.Open(file)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("CatFiles open %v: ", file))
}
_, err = io.Copy(finished, fh)
if err != nil {
return errors.Wrap(err, "CatFiles copy: ")
}
fh.Close()
if remove {
os.Remove(file)
}
}
return nil
}
// SplitFile creates a bunch of smaller files with the data from source splited into them
func SplitFile(fileName string, numPieces int) (err error) {
file, err := os.Open(fileName)
if err != nil {
return err
}
defer file.Close()
fi, err := file.Stat()
if err != nil {
return err
}
bytesPerPiece := int(math.Ceil(float64(fi.Size()) / float64(numPieces)))
bytesRead := 0
i := 0
out, err := os.Create(fileName + "." + strconv.Itoa(i))
if err != nil {
return err
}
buf := make([]byte, 4096)
if bytesPerPiece < 4096/numPieces {
buf = make([]byte, bytesPerPiece)
}
for {
n, err := file.Read(buf)
out.Write(buf[:n])
// If written bytes count is smaller than lenght of buffer
// then we don't create one more empty file
if err == io.EOF || n < len(buf) {
break
}
bytesRead += n
if bytesRead >= bytesPerPiece {
// Close file and open a new one
out.Close()
i++
out, err = os.Create(fileName + "." + strconv.Itoa(i))
if err != nil {
return err
}
bytesRead = 0
}
}
out.Close()
return nil
}
// CopyFile copies a file from src to dst. If src and dst files exist, and are
// the same, then return success. Otherise, attempt to create a hard link
// between the two files. If that fail, copy the file contents from src to dst.
func CopyFile(src, dst string) (err error) {
sfi, err := os.Stat(src)
if err != nil {
return
}
if !sfi.Mode().IsRegular() {
// cannot copy non-regular files (e.g., directories,
// symlinks, devices, etc.)
return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
}
dfi, err := os.Stat(dst)
if err != nil {
if !os.IsNotExist(err) {
return
}
} else {
if !(dfi.Mode().IsRegular()) {
return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
}
if os.SameFile(sfi, dfi) {
return
}
}
if err = os.Link(src, dst); err == nil {
return
}
err = copyFileContents(src, dst)
return
}
// copyFileContents copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file.
func copyFileContents(src, dst string) (err error) {
in, err := os.Open(src)
if err != nil {
return
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return
}
defer func() {
cerr := out.Close()
if err == nil {
err = cerr
}
}()
if _, err = io.Copy(out, in); err != nil {
return
}
err = out.Sync()
return
}
// HashFile does a md5 hash on the file
// from https://golang.org/pkg/crypto/md5/#example_New_file
func HashFile(filename string) (hash string, err error) {
f, err := os.Open(filename)
if err != nil {
return
}
defer f.Close()
h := md5.New()
if _, err = io.Copy(h, f); err != nil {
return
}
hash = fmt.Sprintf("%x", h.Sum(nil))
return
}
// FileSize returns the size of a file
func FileSize(filename string) (int, error) {
fi, err := os.Stat(filename)
if err != nil {
return -1, err
}
size := int(fi.Size())
return size, nil
}

View File

@ -1,119 +0,0 @@
package main
import (
"os"
"testing"
)
func TestSplitFile(t *testing.T) {
err := SplitFile("testing_data/README.md", 3)
if err != nil {
t.Error(err)
}
os.Remove("testing_data/README.md.0")
os.Remove("testing_data/README.md.1")
}
func TestFileSize(t *testing.T) {
t.Run("File is ok ", func(t *testing.T) {
_, err := FileSize("testing_data/README.md")
if err != nil {
t.Errorf("should pass with no error, got: %v", err)
}
})
t.Run("File does not exist", func(t *testing.T) {
s, err := FileSize("testing_data/someStrangeFile")
if err == nil {
t.Error("should return an error")
}
if s != -1 {
t.Errorf("size should be -1, got: %d", s)
}
})
}
func TestHashFile(t *testing.T) {
t.Run("Hash created successfully", func(t *testing.T) {
h, err := HashFile("testing_data/README.md")
if err != nil {
t.Errorf("should pass with no error, got: %v", err)
}
if len(h) != 32 {
t.Errorf("invalid md5 hash, length should be 32 got: %d", len(h))
}
})
t.Run("File does not exist", func(t *testing.T) {
h, err := HashFile("testing_data/someStrangeFile")
if err == nil {
t.Error("should return an error")
}
if len(h) > 0 {
t.Errorf("hash length should be 0, got: %d", len(h))
}
if h != "" {
t.Errorf("hash should be empty string, got: %s", h)
}
})
}
func TestCopyFileContents(t *testing.T) {
t.Run("Content copied successfully", func(t *testing.T) {
f1 := "testing_data/README.md"
f2 := "testing_data/CopyOfREADME.md"
err := copyFileContents(f1, f2)
if err != nil {
t.Errorf("should pass with no error, got: %v", err)
}
f1Length, err := FileSize(f1)
if err != nil {
t.Errorf("can't get file nr1 size: %v", err)
}
f2Length, err := FileSize(f2)
if err != nil {
t.Errorf("can't get file nr2 size: %v", err)
}
if f1Length != f2Length {
t.Errorf("size of both files should be same got: file1: %d file2: %d", f1Length, f2Length)
}
os.Remove(f2)
})
}
func TestCopyFile(t *testing.T) {
t.Run("Files copied successfully", func(t *testing.T) {
f1 := "testing_data/README.md"
f2 := "testing_data/CopyOfREADME.md"
err := CopyFile(f1, f2)
if err != nil {
t.Errorf("should pass with no error, got: %v", err)
}
f1Length, err := FileSize(f1)
if err != nil {
t.Errorf("can't get file nr1 size: %v", err)
}
f2Length, err := FileSize(f2)
if err != nil {
t.Errorf("can't get file nr2 size: %v", err)
}
if f1Length != f2Length {
t.Errorf("size of both files should be same got: file1: %d file2: %d", f1Length, f2Length)
}
os.Remove(f2)
})
}
func TestCatFiles(t *testing.T) {
t.Run("CatFiles passing", func(t *testing.T) {
files := []string{"testing_data/catFile1.txt", "testing_data/catFile2.txt"}
err := CatFiles(files, "testing_data/CatFile.txt", false)
if err != nil {
t.Errorf("should pass with no error, got: %v", err)
}
if _, err := os.Stat("testing_data/CatFile.txt"); os.IsNotExist(err) {
t.Errorf("file were not created: %v", err)
}
os.Remove("testing_data/CatFile.txt")
})
}

View File

@ -1,21 +0,0 @@
sudo: false
language: go
go:
- 1.3.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- master
matrix:
allow_failures:
- go: master
fast_finish: true
install:
- # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d -s .)
- go tool vet .
- go test -v -race ./...

View File

@ -1,21 +0,0 @@
Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net>
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.
<http://www.opensource.org/licenses/mit-license.php>

View File

@ -1,92 +0,0 @@
# Humane Units [![Build Status](https://travis-ci.org/dustin/go-humanize.svg?branch=master)](https://travis-ci.org/dustin/go-humanize) [![GoDoc](https://godoc.org/github.com/dustin/go-humanize?status.svg)](https://godoc.org/github.com/dustin/go-humanize)
Just a few functions for helping humanize times and sizes.
`go get` it as `github.com/dustin/go-humanize`, import it as
`"github.com/dustin/go-humanize"`, use it as `humanize`.
See [godoc](https://godoc.org/github.com/dustin/go-humanize) for
complete documentation.
## Sizes
This lets you take numbers like `82854982` and convert them to useful
strings like, `83 MB` or `79 MiB` (whichever you prefer).
Example:
```go
fmt.Printf("That file is %s.", humanize.Bytes(82854982)) // That file is 83 MB.
```
## Times
This lets you take a `time.Time` and spit it out in relative terms.
For example, `12 seconds ago` or `3 days from now`.
Example:
```go
fmt.Printf("This was touched %s.", humanize.Time(someTimeInstance)) // This was touched 7 hours ago.
```
Thanks to Kyle Lemons for the time implementation from an IRC
conversation one day. It's pretty neat.
## Ordinals
From a [mailing list discussion][odisc] where a user wanted to be able
to label ordinals.
0 -> 0th
1 -> 1st
2 -> 2nd
3 -> 3rd
4 -> 4th
[...]
Example:
```go
fmt.Printf("You're my %s best friend.", humanize.Ordinal(193)) // You are my 193rd best friend.
```
## Commas
Want to shove commas into numbers? Be my guest.
0 -> 0
100 -> 100
1000 -> 1,000
1000000000 -> 1,000,000,000
-100000 -> -100,000
Example:
```go
fmt.Printf("You owe $%s.\n", humanize.Comma(6582491)) // You owe $6,582,491.
```
## Ftoa
Nicer float64 formatter that removes trailing zeros.
```go
fmt.Printf("%f", 2.24) // 2.240000
fmt.Printf("%s", humanize.Ftoa(2.24)) // 2.24
fmt.Printf("%f", 2.0) // 2.000000
fmt.Printf("%s", humanize.Ftoa(2.0)) // 2
```
## SI notation
Format numbers with [SI notation][sinotation].
Example:
```go
humanize.SI(0.00000000223, "M") // 2.23 nM
```
[odisc]: https://groups.google.com/d/topic/golang-nuts/l8NhI74jl-4/discussion
[sinotation]: http://en.wikipedia.org/wiki/Metric_prefix

View File

@ -1,31 +0,0 @@
package humanize
import (
"math/big"
)
// order of magnitude (to a max order)
func oomm(n, b *big.Int, maxmag int) (float64, int) {
mag := 0
m := &big.Int{}
for n.Cmp(b) >= 0 {
n.DivMod(n, b, m)
mag++
if mag == maxmag && maxmag >= 0 {
break
}
}
return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag
}
// total order of magnitude
// (same as above, but with no upper limit)
func oom(n, b *big.Int) (float64, int) {
mag := 0
m := &big.Int{}
for n.Cmp(b) >= 0 {
n.DivMod(n, b, m)
mag++
}
return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag
}

View File

@ -1,173 +0,0 @@
package humanize
import (
"fmt"
"math/big"
"strings"
"unicode"
)
var (
bigIECExp = big.NewInt(1024)
// BigByte is one byte in bit.Ints
BigByte = big.NewInt(1)
// BigKiByte is 1,024 bytes in bit.Ints
BigKiByte = (&big.Int{}).Mul(BigByte, bigIECExp)
// BigMiByte is 1,024 k bytes in bit.Ints
BigMiByte = (&big.Int{}).Mul(BigKiByte, bigIECExp)
// BigGiByte is 1,024 m bytes in bit.Ints
BigGiByte = (&big.Int{}).Mul(BigMiByte, bigIECExp)
// BigTiByte is 1,024 g bytes in bit.Ints
BigTiByte = (&big.Int{}).Mul(BigGiByte, bigIECExp)
// BigPiByte is 1,024 t bytes in bit.Ints
BigPiByte = (&big.Int{}).Mul(BigTiByte, bigIECExp)
// BigEiByte is 1,024 p bytes in bit.Ints
BigEiByte = (&big.Int{}).Mul(BigPiByte, bigIECExp)
// BigZiByte is 1,024 e bytes in bit.Ints
BigZiByte = (&big.Int{}).Mul(BigEiByte, bigIECExp)
// BigYiByte is 1,024 z bytes in bit.Ints
BigYiByte = (&big.Int{}).Mul(BigZiByte, bigIECExp)
)
var (
bigSIExp = big.NewInt(1000)
// BigSIByte is one SI byte in big.Ints
BigSIByte = big.NewInt(1)
// BigKByte is 1,000 SI bytes in big.Ints
BigKByte = (&big.Int{}).Mul(BigSIByte, bigSIExp)
// BigMByte is 1,000 SI k bytes in big.Ints
BigMByte = (&big.Int{}).Mul(BigKByte, bigSIExp)
// BigGByte is 1,000 SI m bytes in big.Ints
BigGByte = (&big.Int{}).Mul(BigMByte, bigSIExp)
// BigTByte is 1,000 SI g bytes in big.Ints
BigTByte = (&big.Int{}).Mul(BigGByte, bigSIExp)
// BigPByte is 1,000 SI t bytes in big.Ints
BigPByte = (&big.Int{}).Mul(BigTByte, bigSIExp)
// BigEByte is 1,000 SI p bytes in big.Ints
BigEByte = (&big.Int{}).Mul(BigPByte, bigSIExp)
// BigZByte is 1,000 SI e bytes in big.Ints
BigZByte = (&big.Int{}).Mul(BigEByte, bigSIExp)
// BigYByte is 1,000 SI z bytes in big.Ints
BigYByte = (&big.Int{}).Mul(BigZByte, bigSIExp)
)
var bigBytesSizeTable = map[string]*big.Int{
"b": BigByte,
"kib": BigKiByte,
"kb": BigKByte,
"mib": BigMiByte,
"mb": BigMByte,
"gib": BigGiByte,
"gb": BigGByte,
"tib": BigTiByte,
"tb": BigTByte,
"pib": BigPiByte,
"pb": BigPByte,
"eib": BigEiByte,
"eb": BigEByte,
"zib": BigZiByte,
"zb": BigZByte,
"yib": BigYiByte,
"yb": BigYByte,
// Without suffix
"": BigByte,
"ki": BigKiByte,
"k": BigKByte,
"mi": BigMiByte,
"m": BigMByte,
"gi": BigGiByte,
"g": BigGByte,
"ti": BigTiByte,
"t": BigTByte,
"pi": BigPiByte,
"p": BigPByte,
"ei": BigEiByte,
"e": BigEByte,
"z": BigZByte,
"zi": BigZiByte,
"y": BigYByte,
"yi": BigYiByte,
}
var ten = big.NewInt(10)
func humanateBigBytes(s, base *big.Int, sizes []string) string {
if s.Cmp(ten) < 0 {
return fmt.Sprintf("%d B", s)
}
c := (&big.Int{}).Set(s)
val, mag := oomm(c, base, len(sizes)-1)
suffix := sizes[mag]
f := "%.0f %s"
if val < 10 {
f = "%.1f %s"
}
return fmt.Sprintf(f, val, suffix)
}
// BigBytes produces a human readable representation of an SI size.
//
// See also: ParseBigBytes.
//
// BigBytes(82854982) -> 83 MB
func BigBytes(s *big.Int) string {
sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
return humanateBigBytes(s, bigSIExp, sizes)
}
// BigIBytes produces a human readable representation of an IEC size.
//
// See also: ParseBigBytes.
//
// BigIBytes(82854982) -> 79 MiB
func BigIBytes(s *big.Int) string {
sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
return humanateBigBytes(s, bigIECExp, sizes)
}
// ParseBigBytes parses a string representation of bytes into the number
// of bytes it represents.
//
// See also: BigBytes, BigIBytes.
//
// ParseBigBytes("42 MB") -> 42000000, nil
// ParseBigBytes("42 mib") -> 44040192, nil
func ParseBigBytes(s string) (*big.Int, error) {
lastDigit := 0
hasComma := false
for _, r := range s {
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
break
}
if r == ',' {
hasComma = true
}
lastDigit++
}
num := s[:lastDigit]
if hasComma {
num = strings.Replace(num, ",", "", -1)
}
val := &big.Rat{}
_, err := fmt.Sscanf(num, "%f", val)
if err != nil {
return nil, err
}
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
if m, ok := bigBytesSizeTable[extra]; ok {
mv := (&big.Rat{}).SetInt(m)
val.Mul(val, mv)
rv := &big.Int{}
rv.Div(val.Num(), val.Denom())
return rv, nil
}
return nil, fmt.Errorf("unhandled size name: %v", extra)
}

View File

@ -1,220 +0,0 @@
package humanize
import (
"math/big"
"testing"
)
func TestBigByteParsing(t *testing.T) {
tests := []struct {
in string
exp uint64
}{
{"42", 42},
{"42MB", 42000000},
{"42MiB", 44040192},
{"42mb", 42000000},
{"42mib", 44040192},
{"42MIB", 44040192},
{"42 MB", 42000000},
{"42 MiB", 44040192},
{"42 mb", 42000000},
{"42 mib", 44040192},
{"42 MIB", 44040192},
{"42.5MB", 42500000},
{"42.5MiB", 44564480},
{"42.5 MB", 42500000},
{"42.5 MiB", 44564480},
// No need to say B
{"42M", 42000000},
{"42Mi", 44040192},
{"42m", 42000000},
{"42mi", 44040192},
{"42MI", 44040192},
{"42 M", 42000000},
{"42 Mi", 44040192},
{"42 m", 42000000},
{"42 mi", 44040192},
{"42 MI", 44040192},
{"42.5M", 42500000},
{"42.5Mi", 44564480},
{"42.5 M", 42500000},
{"42.5 Mi", 44564480},
{"1,005.03 MB", 1005030000},
// Large testing, breaks when too much larger than
// this.
{"12.5 EB", uint64(12.5 * float64(EByte))},
{"12.5 E", uint64(12.5 * float64(EByte))},
{"12.5 EiB", uint64(12.5 * float64(EiByte))},
}
for _, p := range tests {
got, err := ParseBigBytes(p.in)
if err != nil {
t.Errorf("Couldn't parse %v: %v", p.in, err)
} else {
if got.Uint64() != p.exp {
t.Errorf("Expected %v for %v, got %v",
p.exp, p.in, got)
}
}
}
}
func TestBigByteErrors(t *testing.T) {
got, err := ParseBigBytes("84 JB")
if err == nil {
t.Errorf("Expected error, got %v", got)
}
got, err = ParseBigBytes("")
if err == nil {
t.Errorf("Expected error parsing nothing")
}
}
func bbyte(in uint64) string {
return BigBytes((&big.Int{}).SetUint64(in))
}
func bibyte(in uint64) string {
return BigIBytes((&big.Int{}).SetUint64(in))
}
func TestBigBytes(t *testing.T) {
testList{
{"bytes(0)", bbyte(0), "0 B"},
{"bytes(1)", bbyte(1), "1 B"},
{"bytes(803)", bbyte(803), "803 B"},
{"bytes(999)", bbyte(999), "999 B"},
{"bytes(1024)", bbyte(1024), "1.0 kB"},
{"bytes(1MB - 1)", bbyte(MByte - Byte), "1000 kB"},
{"bytes(1MB)", bbyte(1024 * 1024), "1.0 MB"},
{"bytes(1GB - 1K)", bbyte(GByte - KByte), "1000 MB"},
{"bytes(1GB)", bbyte(GByte), "1.0 GB"},
{"bytes(1TB - 1M)", bbyte(TByte - MByte), "1000 GB"},
{"bytes(1TB)", bbyte(TByte), "1.0 TB"},
{"bytes(1PB - 1T)", bbyte(PByte - TByte), "999 TB"},
{"bytes(1PB)", bbyte(PByte), "1.0 PB"},
{"bytes(1PB - 1T)", bbyte(EByte - PByte), "999 PB"},
{"bytes(1EB)", bbyte(EByte), "1.0 EB"},
// Overflows.
// {"bytes(1EB - 1P)", Bytes((KByte*EByte)-PByte), "1023EB"},
{"bytes(0)", bibyte(0), "0 B"},
{"bytes(1)", bibyte(1), "1 B"},
{"bytes(803)", bibyte(803), "803 B"},
{"bytes(1023)", bibyte(1023), "1023 B"},
{"bytes(1024)", bibyte(1024), "1.0 KiB"},
{"bytes(1MB - 1)", bibyte(MiByte - IByte), "1024 KiB"},
{"bytes(1MB)", bibyte(1024 * 1024), "1.0 MiB"},
{"bytes(1GB - 1K)", bibyte(GiByte - KiByte), "1024 MiB"},
{"bytes(1GB)", bibyte(GiByte), "1.0 GiB"},
{"bytes(1TB - 1M)", bibyte(TiByte - MiByte), "1024 GiB"},
{"bytes(1TB)", bibyte(TiByte), "1.0 TiB"},
{"bytes(1PB - 1T)", bibyte(PiByte - TiByte), "1023 TiB"},
{"bytes(1PB)", bibyte(PiByte), "1.0 PiB"},
{"bytes(1PB - 1T)", bibyte(EiByte - PiByte), "1023 PiB"},
{"bytes(1EiB)", bibyte(EiByte), "1.0 EiB"},
// Overflows.
// {"bytes(1EB - 1P)", bibyte((KIByte*EIByte)-PiByte), "1023EB"},
{"bytes(5.5GiB)", bibyte(5.5 * GiByte), "5.5 GiB"},
{"bytes(5.5GB)", bbyte(5.5 * GByte), "5.5 GB"},
}.validate(t)
}
func TestVeryBigBytes(t *testing.T) {
b, _ := (&big.Int{}).SetString("15347691069326346944512", 10)
s := BigBytes(b)
if s != "15 ZB" {
t.Errorf("Expected 15 ZB, got %v", s)
}
s = BigIBytes(b)
if s != "13 ZiB" {
t.Errorf("Expected 13 ZiB, got %v", s)
}
b, _ = (&big.Int{}).SetString("15716035654990179271180288", 10)
s = BigBytes(b)
if s != "16 YB" {
t.Errorf("Expected 16 YB, got %v", s)
}
s = BigIBytes(b)
if s != "13 YiB" {
t.Errorf("Expected 13 YiB, got %v", s)
}
}
func TestVeryVeryBigBytes(t *testing.T) {
b, _ := (&big.Int{}).SetString("16093220510709943573688614912", 10)
s := BigBytes(b)
if s != "16093 YB" {
t.Errorf("Expected 16093 YB, got %v", s)
}
s = BigIBytes(b)
if s != "13312 YiB" {
t.Errorf("Expected 13312 YiB, got %v", s)
}
}
func TestParseVeryBig(t *testing.T) {
tests := []struct {
in string
out string
}{
{"16 ZB", "16000000000000000000000"},
{"16 ZiB", "18889465931478580854784"},
{"16.5 ZB", "16500000000000000000000"},
{"16.5 ZiB", "19479761741837286506496"},
{"16 Z", "16000000000000000000000"},
{"16 Zi", "18889465931478580854784"},
{"16.5 Z", "16500000000000000000000"},
{"16.5 Zi", "19479761741837286506496"},
{"16 YB", "16000000000000000000000000"},
{"16 YiB", "19342813113834066795298816"},
{"16.5 YB", "16500000000000000000000000"},
{"16.5 YiB", "19947276023641381382651904"},
{"16 Y", "16000000000000000000000000"},
{"16 Yi", "19342813113834066795298816"},
{"16.5 Y", "16500000000000000000000000"},
{"16.5 Yi", "19947276023641381382651904"},
}
for _, test := range tests {
x, err := ParseBigBytes(test.in)
if err != nil {
t.Errorf("Error parsing %q: %v", test.in, err)
continue
}
if x.String() != test.out {
t.Errorf("Expected %q for %q, got %v", test.out, test.in, x)
}
}
}
func BenchmarkParseBigBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseBigBytes("16.5 Z")
}
}
func BenchmarkBigBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
bibyte(16.5 * GByte)
}
}

View File

@ -1,143 +0,0 @@
package humanize
import (
"fmt"
"math"
"strconv"
"strings"
"unicode"
)
// IEC Sizes.
// kibis of bits
const (
Byte = 1 << (iota * 10)
KiByte
MiByte
GiByte
TiByte
PiByte
EiByte
)
// SI Sizes.
const (
IByte = 1
KByte = IByte * 1000
MByte = KByte * 1000
GByte = MByte * 1000
TByte = GByte * 1000
PByte = TByte * 1000
EByte = PByte * 1000
)
var bytesSizeTable = map[string]uint64{
"b": Byte,
"kib": KiByte,
"kb": KByte,
"mib": MiByte,
"mb": MByte,
"gib": GiByte,
"gb": GByte,
"tib": TiByte,
"tb": TByte,
"pib": PiByte,
"pb": PByte,
"eib": EiByte,
"eb": EByte,
// Without suffix
"": Byte,
"ki": KiByte,
"k": KByte,
"mi": MiByte,
"m": MByte,
"gi": GiByte,
"g": GByte,
"ti": TiByte,
"t": TByte,
"pi": PiByte,
"p": PByte,
"ei": EiByte,
"e": EByte,
}
func logn(n, b float64) float64 {
return math.Log(n) / math.Log(b)
}
func humanateBytes(s uint64, base float64, sizes []string) string {
if s < 10 {
return fmt.Sprintf("%d B", s)
}
e := math.Floor(logn(float64(s), base))
suffix := sizes[int(e)]
val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10
f := "%.0f %s"
if val < 10 {
f = "%.1f %s"
}
return fmt.Sprintf(f, val, suffix)
}
// Bytes produces a human readable representation of an SI size.
//
// See also: ParseBytes.
//
// Bytes(82854982) -> 83 MB
func Bytes(s uint64) string {
sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
return humanateBytes(s, 1000, sizes)
}
// IBytes produces a human readable representation of an IEC size.
//
// See also: ParseBytes.
//
// IBytes(82854982) -> 79 MiB
func IBytes(s uint64) string {
sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
return humanateBytes(s, 1024, sizes)
}
// ParseBytes parses a string representation of bytes into the number
// of bytes it represents.
//
// See Also: Bytes, IBytes.
//
// ParseBytes("42 MB") -> 42000000, nil
// ParseBytes("42 mib") -> 44040192, nil
func ParseBytes(s string) (uint64, error) {
lastDigit := 0
hasComma := false
for _, r := range s {
if !(unicode.IsDigit(r) || r == '.' || r == ',') {
break
}
if r == ',' {
hasComma = true
}
lastDigit++
}
num := s[:lastDigit]
if hasComma {
num = strings.Replace(num, ",", "", -1)
}
f, err := strconv.ParseFloat(num, 64)
if err != nil {
return 0, err
}
extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
if m, ok := bytesSizeTable[extra]; ok {
f *= float64(m)
if f >= math.MaxUint64 {
return 0, fmt.Errorf("too large: %v", s)
}
return uint64(f), nil
}
return 0, fmt.Errorf("unhandled size name: %v", extra)
}

View File

@ -1,146 +0,0 @@
package humanize
import (
"testing"
)
func TestByteParsing(t *testing.T) {
tests := []struct {
in string
exp uint64
}{
{"42", 42},
{"42MB", 42000000},
{"42MiB", 44040192},
{"42mb", 42000000},
{"42mib", 44040192},
{"42MIB", 44040192},
{"42 MB", 42000000},
{"42 MiB", 44040192},
{"42 mb", 42000000},
{"42 mib", 44040192},
{"42 MIB", 44040192},
{"42.5MB", 42500000},
{"42.5MiB", 44564480},
{"42.5 MB", 42500000},
{"42.5 MiB", 44564480},
// No need to say B
{"42M", 42000000},
{"42Mi", 44040192},
{"42m", 42000000},
{"42mi", 44040192},
{"42MI", 44040192},
{"42 M", 42000000},
{"42 Mi", 44040192},
{"42 m", 42000000},
{"42 mi", 44040192},
{"42 MI", 44040192},
{"42.5M", 42500000},
{"42.5Mi", 44564480},
{"42.5 M", 42500000},
{"42.5 Mi", 44564480},
// Bug #42
{"1,005.03 MB", 1005030000},
// Large testing, breaks when too much larger than
// this.
{"12.5 EB", uint64(12.5 * float64(EByte))},
{"12.5 E", uint64(12.5 * float64(EByte))},
{"12.5 EiB", uint64(12.5 * float64(EiByte))},
}
for _, p := range tests {
got, err := ParseBytes(p.in)
if err != nil {
t.Errorf("Couldn't parse %v: %v", p.in, err)
}
if got != p.exp {
t.Errorf("Expected %v for %v, got %v",
p.exp, p.in, got)
}
}
}
func TestByteErrors(t *testing.T) {
got, err := ParseBytes("84 JB")
if err == nil {
t.Errorf("Expected error, got %v", got)
}
got, err = ParseBytes("")
if err == nil {
t.Errorf("Expected error parsing nothing")
}
got, err = ParseBytes("16 EiB")
if err == nil {
t.Errorf("Expected error, got %v", got)
}
}
func TestBytes(t *testing.T) {
testList{
{"bytes(0)", Bytes(0), "0 B"},
{"bytes(1)", Bytes(1), "1 B"},
{"bytes(803)", Bytes(803), "803 B"},
{"bytes(999)", Bytes(999), "999 B"},
{"bytes(1024)", Bytes(1024), "1.0 kB"},
{"bytes(9999)", Bytes(9999), "10 kB"},
{"bytes(1MB - 1)", Bytes(MByte - Byte), "1000 kB"},
{"bytes(1MB)", Bytes(1024 * 1024), "1.0 MB"},
{"bytes(1GB - 1K)", Bytes(GByte - KByte), "1000 MB"},
{"bytes(1GB)", Bytes(GByte), "1.0 GB"},
{"bytes(1TB - 1M)", Bytes(TByte - MByte), "1000 GB"},
{"bytes(10MB)", Bytes(9999 * 1000), "10 MB"},
{"bytes(1TB)", Bytes(TByte), "1.0 TB"},
{"bytes(1PB - 1T)", Bytes(PByte - TByte), "999 TB"},
{"bytes(1PB)", Bytes(PByte), "1.0 PB"},
{"bytes(1PB - 1T)", Bytes(EByte - PByte), "999 PB"},
{"bytes(1EB)", Bytes(EByte), "1.0 EB"},
// Overflows.
// {"bytes(1EB - 1P)", Bytes((KByte*EByte)-PByte), "1023EB"},
{"bytes(0)", IBytes(0), "0 B"},
{"bytes(1)", IBytes(1), "1 B"},
{"bytes(803)", IBytes(803), "803 B"},
{"bytes(1023)", IBytes(1023), "1023 B"},
{"bytes(1024)", IBytes(1024), "1.0 KiB"},
{"bytes(1MB - 1)", IBytes(MiByte - IByte), "1024 KiB"},
{"bytes(1MB)", IBytes(1024 * 1024), "1.0 MiB"},
{"bytes(1GB - 1K)", IBytes(GiByte - KiByte), "1024 MiB"},
{"bytes(1GB)", IBytes(GiByte), "1.0 GiB"},
{"bytes(1TB - 1M)", IBytes(TiByte - MiByte), "1024 GiB"},
{"bytes(1TB)", IBytes(TiByte), "1.0 TiB"},
{"bytes(1PB - 1T)", IBytes(PiByte - TiByte), "1023 TiB"},
{"bytes(1PB)", IBytes(PiByte), "1.0 PiB"},
{"bytes(1PB - 1T)", IBytes(EiByte - PiByte), "1023 PiB"},
{"bytes(1EiB)", IBytes(EiByte), "1.0 EiB"},
// Overflows.
// {"bytes(1EB - 1P)", IBytes((KIByte*EIByte)-PiByte), "1023EB"},
{"bytes(5.5GiB)", IBytes(5.5 * GiByte), "5.5 GiB"},
{"bytes(5.5GB)", Bytes(5.5 * GByte), "5.5 GB"},
}.validate(t)
}
func BenchmarkParseBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseBytes("16.5 GB")
}
}
func BenchmarkBytes(b *testing.B) {
for i := 0; i < b.N; i++ {
Bytes(16.5 * GByte)
}
}

View File

@ -1,108 +0,0 @@
package humanize
import (
"bytes"
"math"
"math/big"
"strconv"
"strings"
)
// Comma produces a string form of the given number in base 10 with
// commas after every three orders of magnitude.
//
// e.g. Comma(834142) -> 834,142
func Comma(v int64) string {
sign := ""
// minin64 can't be negated to a usable value, so it has to be special cased.
if v == math.MinInt64 {
return "-9,223,372,036,854,775,808"
}
if v < 0 {
sign = "-"
v = 0 - v
}
parts := []string{"", "", "", "", "", "", ""}
j := len(parts) - 1
for v > 999 {
parts[j] = strconv.FormatInt(v%1000, 10)
switch len(parts[j]) {
case 2:
parts[j] = "0" + parts[j]
case 1:
parts[j] = "00" + parts[j]
}
v = v / 1000
j--
}
parts[j] = strconv.Itoa(int(v))
return sign + strings.Join(parts[j:], ",")
}
// Commaf produces a string form of the given number in base 10 with
// commas after every three orders of magnitude.
//
// e.g. Commaf(834142.32) -> 834,142.32
func Commaf(v float64) string {
buf := &bytes.Buffer{}
if v < 0 {
buf.Write([]byte{'-'})
v = 0 - v
}
comma := []byte{','}
parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
pos := 0
if len(parts[0])%3 != 0 {
pos += len(parts[0]) % 3
buf.WriteString(parts[0][:pos])
buf.Write(comma)
}
for ; pos < len(parts[0]); pos += 3 {
buf.WriteString(parts[0][pos : pos+3])
buf.Write(comma)
}
buf.Truncate(buf.Len() - 1)
if len(parts) > 1 {
buf.Write([]byte{'.'})
buf.WriteString(parts[1])
}
return buf.String()
}
// BigComma produces a string form of the given big.Int in base 10
// with commas after every three orders of magnitude.
func BigComma(b *big.Int) string {
sign := ""
if b.Sign() < 0 {
sign = "-"
b.Abs(b)
}
athousand := big.NewInt(1000)
c := (&big.Int{}).Set(b)
_, m := oom(c, athousand)
parts := make([]string, m+1)
j := len(parts) - 1
mod := &big.Int{}
for b.Cmp(athousand) >= 0 {
b.DivMod(b, athousand, mod)
parts[j] = strconv.FormatInt(mod.Int64(), 10)
switch len(parts[j]) {
case 2:
parts[j] = "0" + parts[j]
case 1:
parts[j] = "00" + parts[j]
}
j--
}
parts[j] = strconv.Itoa(int(b.Int64()))
return sign + strings.Join(parts[j:], ",")
}

View File

@ -1,136 +0,0 @@
package humanize
import (
"math"
"math/big"
"testing"
)
func TestCommas(t *testing.T) {
testList{
{"0", Comma(0), "0"},
{"10", Comma(10), "10"},
{"100", Comma(100), "100"},
{"1,000", Comma(1000), "1,000"},
{"10,000", Comma(10000), "10,000"},
{"100,000", Comma(100000), "100,000"},
{"10,000,000", Comma(10000000), "10,000,000"},
{"10,100,000", Comma(10100000), "10,100,000"},
{"10,010,000", Comma(10010000), "10,010,000"},
{"10,001,000", Comma(10001000), "10,001,000"},
{"123,456,789", Comma(123456789), "123,456,789"},
{"maxint", Comma(9.223372e+18), "9,223,372,000,000,000,000"},
{"math.maxint", Comma(math.MaxInt64), "9,223,372,036,854,775,807"},
{"math.minint", Comma(math.MinInt64), "-9,223,372,036,854,775,808"},
{"minint", Comma(-9.223372e+18), "-9,223,372,000,000,000,000"},
{"-123,456,789", Comma(-123456789), "-123,456,789"},
{"-10,100,000", Comma(-10100000), "-10,100,000"},
{"-10,010,000", Comma(-10010000), "-10,010,000"},
{"-10,001,000", Comma(-10001000), "-10,001,000"},
{"-10,000,000", Comma(-10000000), "-10,000,000"},
{"-100,000", Comma(-100000), "-100,000"},
{"-10,000", Comma(-10000), "-10,000"},
{"-1,000", Comma(-1000), "-1,000"},
{"-100", Comma(-100), "-100"},
{"-10", Comma(-10), "-10"},
}.validate(t)
}
func TestCommafs(t *testing.T) {
testList{
{"0", Commaf(0), "0"},
{"10.11", Commaf(10.11), "10.11"},
{"100", Commaf(100), "100"},
{"1,000", Commaf(1000), "1,000"},
{"10,000", Commaf(10000), "10,000"},
{"100,000", Commaf(100000), "100,000"},
{"834,142.32", Commaf(834142.32), "834,142.32"},
{"10,000,000", Commaf(10000000), "10,000,000"},
{"10,100,000", Commaf(10100000), "10,100,000"},
{"10,010,000", Commaf(10010000), "10,010,000"},
{"10,001,000", Commaf(10001000), "10,001,000"},
{"123,456,789", Commaf(123456789), "123,456,789"},
{"maxf64", Commaf(math.MaxFloat64), "179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000"},
{"minf64", Commaf(math.SmallestNonzeroFloat64), "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005"},
{"-123,456,789", Commaf(-123456789), "-123,456,789"},
{"-10,100,000", Commaf(-10100000), "-10,100,000"},
{"-10,010,000", Commaf(-10010000), "-10,010,000"},
{"-10,001,000", Commaf(-10001000), "-10,001,000"},
{"-10,000,000", Commaf(-10000000), "-10,000,000"},
{"-100,000", Commaf(-100000), "-100,000"},
{"-10,000", Commaf(-10000), "-10,000"},
{"-1,000", Commaf(-1000), "-1,000"},
{"-100.11", Commaf(-100.11), "-100.11"},
{"-10", Commaf(-10), "-10"},
}.validate(t)
}
func BenchmarkCommas(b *testing.B) {
for i := 0; i < b.N; i++ {
Comma(1234567890)
}
}
func BenchmarkCommaf(b *testing.B) {
for i := 0; i < b.N; i++ {
Commaf(1234567890.83584)
}
}
func BenchmarkBigCommas(b *testing.B) {
for i := 0; i < b.N; i++ {
BigComma(big.NewInt(1234567890))
}
}
func bigComma(i int64) string {
return BigComma(big.NewInt(i))
}
func TestBigCommas(t *testing.T) {
testList{
{"0", bigComma(0), "0"},
{"10", bigComma(10), "10"},
{"100", bigComma(100), "100"},
{"1,000", bigComma(1000), "1,000"},
{"10,000", bigComma(10000), "10,000"},
{"100,000", bigComma(100000), "100,000"},
{"10,000,000", bigComma(10000000), "10,000,000"},
{"10,100,000", bigComma(10100000), "10,100,000"},
{"10,010,000", bigComma(10010000), "10,010,000"},
{"10,001,000", bigComma(10001000), "10,001,000"},
{"123,456,789", bigComma(123456789), "123,456,789"},
{"maxint", bigComma(9.223372e+18), "9,223,372,000,000,000,000"},
{"minint", bigComma(-9.223372e+18), "-9,223,372,000,000,000,000"},
{"-123,456,789", bigComma(-123456789), "-123,456,789"},
{"-10,100,000", bigComma(-10100000), "-10,100,000"},
{"-10,010,000", bigComma(-10010000), "-10,010,000"},
{"-10,001,000", bigComma(-10001000), "-10,001,000"},
{"-10,000,000", bigComma(-10000000), "-10,000,000"},
{"-100,000", bigComma(-100000), "-100,000"},
{"-10,000", bigComma(-10000), "-10,000"},
{"-1,000", bigComma(-1000), "-1,000"},
{"-100", bigComma(-100), "-100"},
{"-10", bigComma(-10), "-10"},
}.validate(t)
}
func TestVeryBigCommas(t *testing.T) {
tests := []struct{ in, exp string }{
{
"84889279597249724975972597249849757294578485",
"84,889,279,597,249,724,975,972,597,249,849,757,294,578,485",
},
{
"-84889279597249724975972597249849757294578485",
"-84,889,279,597,249,724,975,972,597,249,849,757,294,578,485",
},
}
for _, test := range tests {
n, _ := (&big.Int{}).SetString(test.in, 10)
got := BigComma(n)
if test.exp != got {
t.Errorf("Expected %q, got %q", test.exp, got)
}
}
}

View File

@ -1,40 +0,0 @@
// +build go1.6
package humanize
import (
"bytes"
"math/big"
"strings"
)
// BigCommaf produces a string form of the given big.Float in base 10
// with commas after every three orders of magnitude.
func BigCommaf(v *big.Float) string {
buf := &bytes.Buffer{}
if v.Sign() < 0 {
buf.Write([]byte{'-'})
v.Abs(v)
}
comma := []byte{','}
parts := strings.Split(v.Text('f', -1), ".")
pos := 0
if len(parts[0])%3 != 0 {
pos += len(parts[0]) % 3
buf.WriteString(parts[0][:pos])
buf.Write(comma)
}
for ; pos < len(parts[0]); pos += 3 {
buf.WriteString(parts[0][pos : pos+3])
buf.Write(comma)
}
buf.Truncate(buf.Len() - 1)
if len(parts) > 1 {
buf.Write([]byte{'.'})
buf.WriteString(parts[1])
}
return buf.String()
}

View File

@ -1,44 +0,0 @@
// +build go1.6
package humanize
import (
"math"
"math/big"
"testing"
)
func BenchmarkBigCommaf(b *testing.B) {
for i := 0; i < b.N; i++ {
Commaf(1234567890.83584)
}
}
func TestBigCommafs(t *testing.T) {
testList{
{"0", BigCommaf(big.NewFloat(0)), "0"},
{"10.11", BigCommaf(big.NewFloat(10.11)), "10.11"},
{"100", BigCommaf(big.NewFloat(100)), "100"},
{"1,000", BigCommaf(big.NewFloat(1000)), "1,000"},
{"10,000", BigCommaf(big.NewFloat(10000)), "10,000"},
{"100,000", BigCommaf(big.NewFloat(100000)), "100,000"},
{"834,142.32", BigCommaf(big.NewFloat(834142.32)), "834,142.32"},
{"10,000,000", BigCommaf(big.NewFloat(10000000)), "10,000,000"},
{"10,100,000", BigCommaf(big.NewFloat(10100000)), "10,100,000"},
{"10,010,000", BigCommaf(big.NewFloat(10010000)), "10,010,000"},
{"10,001,000", BigCommaf(big.NewFloat(10001000)), "10,001,000"},
{"123,456,789", BigCommaf(big.NewFloat(123456789)), "123,456,789"},
{"maxf64", BigCommaf(big.NewFloat(math.MaxFloat64)), "179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000"},
{"minf64", BigCommaf(big.NewFloat(math.SmallestNonzeroFloat64)), "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465"},
{"-123,456,789", BigCommaf(big.NewFloat(-123456789)), "-123,456,789"},
{"-10,100,000", BigCommaf(big.NewFloat(-10100000)), "-10,100,000"},
{"-10,010,000", BigCommaf(big.NewFloat(-10010000)), "-10,010,000"},
{"-10,001,000", BigCommaf(big.NewFloat(-10001000)), "-10,001,000"},
{"-10,000,000", BigCommaf(big.NewFloat(-10000000)), "-10,000,000"},
{"-100,000", BigCommaf(big.NewFloat(-100000)), "-100,000"},
{"-10,000", BigCommaf(big.NewFloat(-10000)), "-10,000"},
{"-1,000", BigCommaf(big.NewFloat(-1000)), "-1,000"},
{"-100.11", BigCommaf(big.NewFloat(-100.11)), "-100.11"},
{"-10", BigCommaf(big.NewFloat(-10)), "-10"},
}.validate(t)
}

View File

@ -1,18 +0,0 @@
package humanize
import (
"testing"
)
type testList []struct {
name, got, exp string
}
func (tl testList) validate(t *testing.T) {
for _, test := range tl {
if test.got != test.exp {
t.Errorf("On %v, expected '%v', but got '%v'",
test.name, test.exp, test.got)
}
}
}

View File

@ -1,23 +0,0 @@
package humanize
import "strconv"
func stripTrailingZeros(s string) string {
offset := len(s) - 1
for offset > 0 {
if s[offset] == '.' {
offset--
break
}
if s[offset] != '0' {
break
}
offset--
}
return s[:offset+1]
}
// Ftoa converts a float to a string with no trailing zeros.
func Ftoa(num float64) string {
return stripTrailingZeros(strconv.FormatFloat(num, 'f', 6, 64))
}

View File

@ -1,55 +0,0 @@
package humanize
import (
"fmt"
"regexp"
"strconv"
"testing"
)
func TestFtoa(t *testing.T) {
testList{
{"200", Ftoa(200), "200"},
{"2", Ftoa(2), "2"},
{"2.2", Ftoa(2.2), "2.2"},
{"2.02", Ftoa(2.02), "2.02"},
{"200.02", Ftoa(200.02), "200.02"},
}.validate(t)
}
func BenchmarkFtoaRegexTrailing(b *testing.B) {
trailingZerosRegex := regexp.MustCompile(`\.?0+$`)
b.ResetTimer()
for i := 0; i < b.N; i++ {
trailingZerosRegex.ReplaceAllString("2.00000", "")
trailingZerosRegex.ReplaceAllString("2.0000", "")
trailingZerosRegex.ReplaceAllString("2.000", "")
trailingZerosRegex.ReplaceAllString("2.00", "")
trailingZerosRegex.ReplaceAllString("2.0", "")
trailingZerosRegex.ReplaceAllString("2", "")
}
}
func BenchmarkFtoaFunc(b *testing.B) {
for i := 0; i < b.N; i++ {
stripTrailingZeros("2.00000")
stripTrailingZeros("2.0000")
stripTrailingZeros("2.000")
stripTrailingZeros("2.00")
stripTrailingZeros("2.0")
stripTrailingZeros("2")
}
}
func BenchmarkFmtF(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprintf("%f", 2.03584)
}
}
func BenchmarkStrconvF(b *testing.B) {
for i := 0; i < b.N; i++ {
strconv.FormatFloat(2.03584, 'f', 6, 64)
}
}

View File

@ -1,8 +0,0 @@
/*
Package humanize converts boring ugly numbers to human-friendly strings and back.
Durations can be turned into strings such as "3 days ago", numbers
representing sizes like 82854982 into useful strings like, "83 MB" or
"79 MiB" (whichever you prefer).
*/
package humanize

View File

@ -1,192 +0,0 @@
package humanize
/*
Slightly adapted from the source to fit go-humanize.
Author: https://github.com/gorhill
Source: https://gist.github.com/gorhill/5285193
*/
import (
"math"
"strconv"
)
var (
renderFloatPrecisionMultipliers = [...]float64{
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
}
renderFloatPrecisionRounders = [...]float64{
0.5,
0.05,
0.005,
0.0005,
0.00005,
0.000005,
0.0000005,
0.00000005,
0.000000005,
0.0000000005,
}
)
// FormatFloat produces a formatted number as string based on the following user-specified criteria:
// * thousands separator
// * decimal separator
// * decimal precision
//
// Usage: s := RenderFloat(format, n)
// The format parameter tells how to render the number n.
//
// See examples: http://play.golang.org/p/LXc1Ddm1lJ
//
// Examples of format strings, given n = 12345.6789:
// "#,###.##" => "12,345.67"
// "#,###." => "12,345"
// "#,###" => "12345,678"
// "#\u202F###,##" => "12345,68"
// "#.###,###### => 12.345,678900
// "" (aka default format) => 12,345.67
//
// The highest precision allowed is 9 digits after the decimal symbol.
// There is also a version for integer number, FormatInteger(),
// which is convenient for calls within template.
func FormatFloat(format string, n float64) string {
// Special cases:
// NaN = "NaN"
// +Inf = "+Infinity"
// -Inf = "-Infinity"
if math.IsNaN(n) {
return "NaN"
}
if n > math.MaxFloat64 {
return "Infinity"
}
if n < -math.MaxFloat64 {
return "-Infinity"
}
// default format
precision := 2
decimalStr := "."
thousandStr := ","
positiveStr := ""
negativeStr := "-"
if len(format) > 0 {
format := []rune(format)
// If there is an explicit format directive,
// then default values are these:
precision = 9
thousandStr = ""
// collect indices of meaningful formatting directives
formatIndx := []int{}
for i, char := range format {
if char != '#' && char != '0' {
formatIndx = append(formatIndx, i)
}
}
if len(formatIndx) > 0 {
// Directive at index 0:
// Must be a '+'
// Raise an error if not the case
// index: 0123456789
// +0.000,000
// +000,000.0
// +0000.00
// +0000
if formatIndx[0] == 0 {
if format[formatIndx[0]] != '+' {
panic("RenderFloat(): invalid positive sign directive")
}
positiveStr = "+"
formatIndx = formatIndx[1:]
}
// Two directives:
// First is thousands separator
// Raise an error if not followed by 3-digit
// 0123456789
// 0.000,000
// 000,000.00
if len(formatIndx) == 2 {
if (formatIndx[1] - formatIndx[0]) != 4 {
panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
}
thousandStr = string(format[formatIndx[0]])
formatIndx = formatIndx[1:]
}
// One directive:
// Directive is decimal separator
// The number of digit-specifier following the separator indicates wanted precision
// 0123456789
// 0.00
// 000,0000
if len(formatIndx) == 1 {
decimalStr = string(format[formatIndx[0]])
precision = len(format) - formatIndx[0] - 1
}
}
}
// generate sign part
var signStr string
if n >= 0.000000001 {
signStr = positiveStr
} else if n <= -0.000000001 {
signStr = negativeStr
n = -n
} else {
signStr = ""
n = 0.0
}
// split number into integer and fractional parts
intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])
// generate integer part string
intStr := strconv.FormatInt(int64(intf), 10)
// add thousand separator if required
if len(thousandStr) > 0 {
for i := len(intStr); i > 3; {
i -= 3
intStr = intStr[:i] + thousandStr + intStr[i:]
}
}
// no fractional part, we can leave now
if precision == 0 {
return signStr + intStr
}
// generate fractional part
fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
// may need padding
if len(fracStr) < precision {
fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
}
return signStr + intStr + decimalStr + fracStr
}
// FormatInteger produces a formatted number as string.
// See FormatFloat.
func FormatInteger(format string, n int) string {
return FormatFloat(format, float64(n))
}

View File

@ -1,79 +0,0 @@
package humanize
import (
"math"
"testing"
)
type TestStruct struct {
name string
format string
num float64
formatted string
}
func TestFormatFloat(t *testing.T) {
tests := []TestStruct{
{"default", "", 12345.6789, "12,345.68"},
{"#", "#", 12345.6789, "12345.678900000"},
{"#.", "#.", 12345.6789, "12346"},
{"#,#", "#,#", 12345.6789, "12345,7"},
{"#,##", "#,##", 12345.6789, "12345,68"},
{"#,###", "#,###", 12345.6789, "12345,679"},
{"#,###.", "#,###.", 12345.6789, "12,346"},
{"#,###.##", "#,###.##", 12345.6789, "12,345.68"},
{"#,###.###", "#,###.###", 12345.6789, "12,345.679"},
{"#,###.####", "#,###.####", 12345.6789, "12,345.6789"},
{"#.###,######", "#.###,######", 12345.6789, "12.345,678900"},
{"bug46", "#,###.##", 52746220055.92342, "52,746,220,055.92"},
{"#\u202f###,##", "#\u202f###,##", 12345.6789, "12345,68"},
// special cases
{"NaN", "#", math.NaN(), "NaN"},
{"+Inf", "#", math.Inf(1), "Infinity"},
{"-Inf", "#", math.Inf(-1), "-Infinity"},
{"signStr <= -0.000000001", "", -0.000000002, "-0.00"},
{"signStr = 0", "", 0, "0.00"},
{"Format directive must start with +", "+000", 12345.6789, "+12345.678900000"},
}
for _, test := range tests {
got := FormatFloat(test.format, test.num)
if got != test.formatted {
t.Errorf("On %v (%v, %v), got %v, wanted %v",
test.name, test.format, test.num, got, test.formatted)
}
}
// Test a single integer
got := FormatInteger("#", 12345)
if got != "12345.000000000" {
t.Errorf("On %v (%v, %v), got %v, wanted %v",
"integerTest", "#", 12345, got, "12345.000000000")
}
// Test the things that could panic
panictests := []TestStruct{
{"RenderFloat(): invalid positive sign directive", "-", 12345.6789, "12,345.68"},
{"RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers", "0.01", 12345.6789, "12,345.68"},
}
for _, test := range panictests {
didPanic := false
var message interface{}
func() {
defer func() {
if message = recover(); message != nil {
didPanic = true
}
}()
// call the target function
_ = FormatFloat(test.format, test.num)
}()
if didPanic != true {
t.Errorf("On %v, should have panic and did not.",
test.name)
}
}
}

View File

@ -1,25 +0,0 @@
package humanize
import "strconv"
// Ordinal gives you the input number in a rank/ordinal format.
//
// Ordinal(3) -> 3rd
func Ordinal(x int) string {
suffix := "th"
switch x % 10 {
case 1:
if x%100 != 11 {
suffix = "st"
}
case 2:
if x%100 != 12 {
suffix = "nd"
}
case 3:
if x%100 != 13 {
suffix = "rd"
}
}
return strconv.Itoa(x) + suffix
}

View File

@ -1,22 +0,0 @@
package humanize
import (
"testing"
)
func TestOrdinals(t *testing.T) {
testList{
{"0", Ordinal(0), "0th"},
{"1", Ordinal(1), "1st"},
{"2", Ordinal(2), "2nd"},
{"3", Ordinal(3), "3rd"},
{"4", Ordinal(4), "4th"},
{"10", Ordinal(10), "10th"},
{"11", Ordinal(11), "11th"},
{"12", Ordinal(12), "12th"},
{"13", Ordinal(13), "13th"},
{"101", Ordinal(101), "101st"},
{"102", Ordinal(102), "102nd"},
{"103", Ordinal(103), "103rd"},
}.validate(t)
}

View File

@ -1,113 +0,0 @@
package humanize
import (
"errors"
"math"
"regexp"
"strconv"
)
var siPrefixTable = map[float64]string{
-24: "y", // yocto
-21: "z", // zepto
-18: "a", // atto
-15: "f", // femto
-12: "p", // pico
-9: "n", // nano
-6: "µ", // micro
-3: "m", // milli
0: "",
3: "k", // kilo
6: "M", // mega
9: "G", // giga
12: "T", // tera
15: "P", // peta
18: "E", // exa
21: "Z", // zetta
24: "Y", // yotta
}
var revSIPrefixTable = revfmap(siPrefixTable)
// revfmap reverses the map and precomputes the power multiplier
func revfmap(in map[float64]string) map[string]float64 {
rv := map[string]float64{}
for k, v := range in {
rv[v] = math.Pow(10, k)
}
return rv
}
var riParseRegex *regexp.Regexp
func init() {
ri := `^([\-0-9.]+)\s?([`
for _, v := range siPrefixTable {
ri += v
}
ri += `]?)(.*)`
riParseRegex = regexp.MustCompile(ri)
}
// ComputeSI finds the most appropriate SI prefix for the given number
// and returns the prefix along with the value adjusted to be within
// that prefix.
//
// See also: SI, ParseSI.
//
// e.g. ComputeSI(2.2345e-12) -> (2.2345, "p")
func ComputeSI(input float64) (float64, string) {
if input == 0 {
return 0, ""
}
mag := math.Abs(input)
exponent := math.Floor(logn(mag, 10))
exponent = math.Floor(exponent/3) * 3
value := mag / math.Pow(10, exponent)
// Handle special case where value is exactly 1000.0
// Should return 1 M instead of 1000 k
if value == 1000.0 {
exponent += 3
value = mag / math.Pow(10, exponent)
}
value = math.Copysign(value, input)
prefix := siPrefixTable[exponent]
return value, prefix
}
// SI returns a string with default formatting.
//
// SI uses Ftoa to format float value, removing trailing zeros.
//
// See also: ComputeSI, ParseSI.
//
// e.g. SI(1000000, "B") -> 1 MB
// e.g. SI(2.2345e-12, "F") -> 2.2345 pF
func SI(input float64, unit string) string {
value, prefix := ComputeSI(input)
return Ftoa(value) + " " + prefix + unit
}
var errInvalid = errors.New("invalid input")
// ParseSI parses an SI string back into the number and unit.
//
// See also: SI, ComputeSI.
//
// e.g. ParseSI("2.2345 pF") -> (2.2345e-12, "F", nil)
func ParseSI(input string) (float64, string, error) {
found := riParseRegex.FindStringSubmatch(input)
if len(found) != 4 {
return 0, "", errInvalid
}
mag := revSIPrefixTable[found[2]]
unit := found[3]
base, err := strconv.ParseFloat(found[1], 64)
return base * mag, unit, err
}

View File

@ -1,101 +0,0 @@
package humanize
import (
"math"
"testing"
)
func TestSI(t *testing.T) {
tests := []struct {
name string
num float64
formatted string
}{
{"e-24", 1e-24, "1 yF"},
{"e-21", 1e-21, "1 zF"},
{"e-18", 1e-18, "1 aF"},
{"e-15", 1e-15, "1 fF"},
{"e-12", 1e-12, "1 pF"},
{"e-12", 2.2345e-12, "2.2345 pF"},
{"e-12", 2.23e-12, "2.23 pF"},
{"e-11", 2.23e-11, "22.3 pF"},
{"e-10", 2.2e-10, "220 pF"},
{"e-9", 2.2e-9, "2.2 nF"},
{"e-8", 2.2e-8, "22 nF"},
{"e-7", 2.2e-7, "220 nF"},
{"e-6", 2.2e-6, "2.2 µF"},
{"e-6", 1e-6, "1 µF"},
{"e-5", 2.2e-5, "22 µF"},
{"e-4", 2.2e-4, "220 µF"},
{"e-3", 2.2e-3, "2.2 mF"},
{"e-2", 2.2e-2, "22 mF"},
{"e-1", 2.2e-1, "220 mF"},
{"e+0", 2.2e-0, "2.2 F"},
{"e+0", 2.2, "2.2 F"},
{"e+1", 2.2e+1, "22 F"},
{"0", 0, "0 F"},
{"e+1", 22, "22 F"},
{"e+2", 2.2e+2, "220 F"},
{"e+2", 220, "220 F"},
{"e+3", 2.2e+3, "2.2 kF"},
{"e+3", 2200, "2.2 kF"},
{"e+4", 2.2e+4, "22 kF"},
{"e+4", 22000, "22 kF"},
{"e+5", 2.2e+5, "220 kF"},
{"e+6", 2.2e+6, "2.2 MF"},
{"e+6", 1e+6, "1 MF"},
{"e+7", 2.2e+7, "22 MF"},
{"e+8", 2.2e+8, "220 MF"},
{"e+9", 2.2e+9, "2.2 GF"},
{"e+10", 2.2e+10, "22 GF"},
{"e+11", 2.2e+11, "220 GF"},
{"e+12", 2.2e+12, "2.2 TF"},
{"e+15", 2.2e+15, "2.2 PF"},
{"e+18", 2.2e+18, "2.2 EF"},
{"e+21", 2.2e+21, "2.2 ZF"},
{"e+24", 2.2e+24, "2.2 YF"},
// special case
{"1F", 1000 * 1000, "1 MF"},
{"1F", 1e6, "1 MF"},
// negative number
{"-100 F", -100, "-100 F"},
}
for _, test := range tests {
got := SI(test.num, "F")
if got != test.formatted {
t.Errorf("On %v (%v), got %v, wanted %v",
test.name, test.num, got, test.formatted)
}
gotf, gotu, err := ParseSI(test.formatted)
if err != nil {
t.Errorf("Error parsing %v (%v): %v", test.name, test.formatted, err)
continue
}
if math.Abs(1-(gotf/test.num)) > 0.01 {
t.Errorf("On %v (%v), got %v, wanted %v (±%v)",
test.name, test.formatted, gotf, test.num,
math.Abs(1-(gotf/test.num)))
}
if gotu != "F" {
t.Errorf("On %v (%v), expected unit F, got %v",
test.name, test.formatted, gotu)
}
}
// Parse error
gotf, gotu, err := ParseSI("x1.21JW") // 1.21 jigga whats
if err == nil {
t.Errorf("Expected error on x1.21JW, got %v %v", gotf, gotu)
}
}
func BenchmarkParseSI(b *testing.B) {
for i := 0; i < b.N; i++ {
ParseSI("2.2346ZB")
}
}

View File

@ -1,117 +0,0 @@
package humanize
import (
"fmt"
"math"
"sort"
"time"
)
// Seconds-based time units
const (
Day = 24 * time.Hour
Week = 7 * Day
Month = 30 * Day
Year = 12 * Month
LongTime = 37 * Year
)
// Time formats a time into a relative string.
//
// Time(someT) -> "3 weeks ago"
func Time(then time.Time) string {
return RelTime(then, time.Now(), "ago", "from now")
}
// A RelTimeMagnitude struct contains a relative time point at which
// the relative format of time will switch to a new format string. A
// slice of these in ascending order by their "D" field is passed to
// CustomRelTime to format durations.
//
// The Format field is a string that may contain a "%s" which will be
// replaced with the appropriate signed label (e.g. "ago" or "from
// now") and a "%d" that will be replaced by the quantity.
//
// The DivBy field is the amount of time the time difference must be
// divided by in order to display correctly.
//
// e.g. if D is 2*time.Minute and you want to display "%d minutes %s"
// DivBy should be time.Minute so whatever the duration is will be
// expressed in minutes.
type RelTimeMagnitude struct {
D time.Duration
Format string
DivBy time.Duration
}
var defaultMagnitudes = []RelTimeMagnitude{
{time.Second, "now", time.Second},
{2 * time.Second, "1 second %s", 1},
{time.Minute, "%d seconds %s", time.Second},
{2 * time.Minute, "1 minute %s", 1},
{time.Hour, "%d minutes %s", time.Minute},
{2 * time.Hour, "1 hour %s", 1},
{Day, "%d hours %s", time.Hour},
{2 * Day, "1 day %s", 1},
{Week, "%d days %s", Day},
{2 * Week, "1 week %s", 1},
{Month, "%d weeks %s", Week},
{2 * Month, "1 month %s", 1},
{Year, "%d months %s", Month},
{18 * Month, "1 year %s", 1},
{2 * Year, "2 years %s", 1},
{LongTime, "%d years %s", Year},
{math.MaxInt64, "a long while %s", 1},
}
// RelTime formats a time into a relative string.
//
// It takes two times and two labels. In addition to the generic time
// delta string (e.g. 5 minutes), the labels are used applied so that
// the label corresponding to the smaller time is applied.
//
// RelTime(timeInPast, timeInFuture, "earlier", "later") -> "3 weeks earlier"
func RelTime(a, b time.Time, albl, blbl string) string {
return CustomRelTime(a, b, albl, blbl, defaultMagnitudes)
}
// CustomRelTime formats a time into a relative string.
//
// It takes two times two labels and a table of relative time formats.
// In addition to the generic time delta string (e.g. 5 minutes), the
// labels are used applied so that the label corresponding to the
// smaller time is applied.
func CustomRelTime(a, b time.Time, albl, blbl string, magnitudes []RelTimeMagnitude) string {
lbl := albl
diff := b.Sub(a)
if a.After(b) {
lbl = blbl
diff = a.Sub(b)
}
n := sort.Search(len(magnitudes), func(i int) bool {
return magnitudes[i].D >= diff
})
if n >= len(magnitudes) {
n = len(magnitudes) - 1
}
mag := magnitudes[n]
args := []interface{}{}
escaped := false
for _, ch := range mag.Format {
if escaped {
switch ch {
case 's':
args = append(args, lbl)
case 'd':
args = append(args, diff/mag.DivBy)
}
escaped = false
} else {
escaped = ch == '%'
}
}
return fmt.Sprintf(mag.Format, args...)
}

View File

@ -1,113 +0,0 @@
package humanize
import (
"math"
"testing"
"time"
)
func TestPast(t *testing.T) {
now := time.Now()
testList{
{"now", Time(now), "now"},
{"1 second ago", Time(now.Add(-1 * time.Second)), "1 second ago"},
{"12 seconds ago", Time(now.Add(-12 * time.Second)), "12 seconds ago"},
{"30 seconds ago", Time(now.Add(-30 * time.Second)), "30 seconds ago"},
{"45 seconds ago", Time(now.Add(-45 * time.Second)), "45 seconds ago"},
{"1 minute ago", Time(now.Add(-63 * time.Second)), "1 minute ago"},
{"15 minutes ago", Time(now.Add(-15 * time.Minute)), "15 minutes ago"},
{"1 hour ago", Time(now.Add(-63 * time.Minute)), "1 hour ago"},
{"2 hours ago", Time(now.Add(-2 * time.Hour)), "2 hours ago"},
{"21 hours ago", Time(now.Add(-21 * time.Hour)), "21 hours ago"},
{"1 day ago", Time(now.Add(-26 * time.Hour)), "1 day ago"},
{"2 days ago", Time(now.Add(-49 * time.Hour)), "2 days ago"},
{"3 days ago", Time(now.Add(-3 * Day)), "3 days ago"},
{"1 week ago (1)", Time(now.Add(-7 * Day)), "1 week ago"},
{"1 week ago (2)", Time(now.Add(-12 * Day)), "1 week ago"},
{"2 weeks ago", Time(now.Add(-15 * Day)), "2 weeks ago"},
{"1 month ago", Time(now.Add(-39 * Day)), "1 month ago"},
{"3 months ago", Time(now.Add(-99 * Day)), "3 months ago"},
{"1 year ago (1)", Time(now.Add(-365 * Day)), "1 year ago"},
{"1 year ago (1)", Time(now.Add(-400 * Day)), "1 year ago"},
{"2 years ago (1)", Time(now.Add(-548 * Day)), "2 years ago"},
{"2 years ago (2)", Time(now.Add(-725 * Day)), "2 years ago"},
{"2 years ago (3)", Time(now.Add(-800 * Day)), "2 years ago"},
{"3 years ago", Time(now.Add(-3 * Year)), "3 years ago"},
{"long ago", Time(now.Add(-LongTime)), "a long while ago"},
}.validate(t)
}
func TestFuture(t *testing.T) {
// Add a little time so that these things properly line up in
// the future.
now := time.Now().Add(time.Millisecond * 250)
testList{
{"now", Time(now), "now"},
{"1 second from now", Time(now.Add(+1 * time.Second)), "1 second from now"},
{"12 seconds from now", Time(now.Add(+12 * time.Second)), "12 seconds from now"},
{"30 seconds from now", Time(now.Add(+30 * time.Second)), "30 seconds from now"},
{"45 seconds from now", Time(now.Add(+45 * time.Second)), "45 seconds from now"},
{"15 minutes from now", Time(now.Add(+15 * time.Minute)), "15 minutes from now"},
{"2 hours from now", Time(now.Add(+2 * time.Hour)), "2 hours from now"},
{"21 hours from now", Time(now.Add(+21 * time.Hour)), "21 hours from now"},
{"1 day from now", Time(now.Add(+26 * time.Hour)), "1 day from now"},
{"2 days from now", Time(now.Add(+49 * time.Hour)), "2 days from now"},
{"3 days from now", Time(now.Add(+3 * Day)), "3 days from now"},
{"1 week from now (1)", Time(now.Add(+7 * Day)), "1 week from now"},
{"1 week from now (2)", Time(now.Add(+12 * Day)), "1 week from now"},
{"2 weeks from now", Time(now.Add(+15 * Day)), "2 weeks from now"},
{"1 month from now", Time(now.Add(+30 * Day)), "1 month from now"},
{"1 year from now", Time(now.Add(+365 * Day)), "1 year from now"},
{"2 years from now", Time(now.Add(+2 * Year)), "2 years from now"},
{"a while from now", Time(now.Add(+LongTime)), "a long while from now"},
}.validate(t)
}
func TestRange(t *testing.T) {
start := time.Time{}
end := time.Unix(math.MaxInt64, math.MaxInt64)
x := RelTime(start, end, "ago", "from now")
if x != "a long while from now" {
t.Errorf("Expected a long while from now, got %q", x)
}
}
func TestCustomRelTime(t *testing.T) {
now := time.Now().Add(time.Millisecond * 250)
magnitudes := []RelTimeMagnitude{
{time.Second, "now", time.Second},
{2 * time.Second, "1 second %s", 1},
{time.Minute, "%d seconds %s", time.Second},
{Day - time.Second, "%d minutes %s", time.Minute},
{Day, "%d hours %s", time.Hour},
{2 * Day, "1 day %s", 1},
{Week, "%d days %s", Day},
{2 * Week, "1 week %s", 1},
{6 * Month, "%d weeks %s", Week},
{Year, "%d months %s", Month},
}
customRelTime := func(then time.Time) string {
return CustomRelTime(then, time.Now(), "ago", "from now", magnitudes)
}
testList{
{"now", customRelTime(now), "now"},
{"1 second from now", customRelTime(now.Add(+1 * time.Second)), "1 second from now"},
{"12 seconds from now", customRelTime(now.Add(+12 * time.Second)), "12 seconds from now"},
{"30 seconds from now", customRelTime(now.Add(+30 * time.Second)), "30 seconds from now"},
{"45 seconds from now", customRelTime(now.Add(+45 * time.Second)), "45 seconds from now"},
{"15 minutes from now", customRelTime(now.Add(+15 * time.Minute)), "15 minutes from now"},
{"2 hours from now", customRelTime(now.Add(+2 * time.Hour)), "120 minutes from now"},
{"21 hours from now", customRelTime(now.Add(+21 * time.Hour)), "1260 minutes from now"},
{"1 day from now", customRelTime(now.Add(+26 * time.Hour)), "1 day from now"},
{"2 days from now", customRelTime(now.Add(+49 * time.Hour)), "2 days from now"},
{"3 days from now", customRelTime(now.Add(+3 * Day)), "3 days from now"},
{"1 week from now (1)", customRelTime(now.Add(+7 * Day)), "1 week from now"},
{"1 week from now (2)", customRelTime(now.Add(+12 * Day)), "1 week from now"},
{"2 weeks from now", customRelTime(now.Add(+15 * Day)), "2 weeks from now"},
{"1 month from now", customRelTime(now.Add(+30 * Day)), "4 weeks from now"},
{"6 months from now", customRelTime(now.Add(+6*Month - time.Second)), "25 weeks from now"},
{"1 year from now", customRelTime(now.Add(+365 * Day)), "12 months from now"},
{"2 years from now", customRelTime(now.Add(+2 * Year)), "24 months from now"},
{"a while from now", customRelTime(now.Add(+LongTime)), "444 months from now"},
}.validate(t)
}

View File

@ -1 +0,0 @@
crypt/crypt

View File

@ -1,13 +0,0 @@
Copyright (c) 2013 Markus Sonderegger
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -1,4 +0,0 @@
# crypt
Package crypt provides password-based encryption and decryption of
data streams.

View File

@ -1,165 +0,0 @@
// Package crypt provides password-based encryption and decryption of
// data streams.
package crypt
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/hmac"
"crypto/rand"
"errors"
"hash"
"io"
)
const (
blockSize = aes.BlockSize // AES block size
version = 1
)
// Crypter encrypt/decrypts with AES (Rijndael) in cipher block counter
// mode (CTR) and authenticate with HMAC-SHA.
type Crypter struct {
HashFunc func() hash.Hash
HashSize int
Key Key
BufSize int
}
func (c *Crypter) encHeader(salt, iv, hmacKey []byte) []byte {
keySize := c.Key.Size()
headerSize := 1 + keySize + blockSize + c.HashSize
b := make([]byte, headerSize)
b[0] = version
copy(b[1:1+keySize], salt)
copy(b[1+keySize:1+keySize+blockSize], iv)
mac := hmac.New(c.HashFunc, hmacKey)
mac.Write(b[:1+keySize+blockSize])
copy(b[1+keySize+blockSize:], mac.Sum(nil))
return b
}
func (c *Crypter) bufSize() int {
if c.BufSize == 0 {
return 2 * 1024 * 1024
}
return c.BufSize
}
func (c *Crypter) decHeader(b []byte) ([]byte, []byte, error) {
if b[0] != version {
return nil, nil, errors.New("malformed encrypted packet")
}
keySize := c.Key.Size()
salt := b[1 : 1+keySize]
iv := b[1+keySize : 1+keySize+blockSize]
return salt, iv, nil
}
// Encrypt encrypts from src until either EOF is reached on src or an
// error occurs. A successful Encrypt returns err == nil, not err == EOF.
func (c *Crypter) Encrypt(dst io.Writer, src io.Reader) (err error) {
salt := make([]byte, c.Key.Size())
if _, err := rand.Read(salt); err != nil {
return err
}
iv := make([]byte, blockSize)
if _, err := rand.Read(iv); err != nil {
return err
}
aesKey, hmacKey := c.Key.Derive(salt)
header := c.encHeader(salt, iv, hmacKey)
if _, err := dst.Write(header); err != nil {
return err
}
mac := hmac.New(c.HashFunc, hmacKey)
mac.Write(header)
block, err := aes.NewCipher(aesKey)
if err != nil {
return err
}
stream := cipher.NewCTR(block, iv)
buf := make([]byte, c.bufSize())
n := 0
for {
n, err = src.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return err
}
mac.Write(buf[:n])
stream.XORKeyStream(buf[:n], buf[:n])
if _, err = dst.Write(buf[:n]); err != nil {
return err
}
if _, err = dst.Write(mac.Sum(nil)); err != nil {
return err
}
}
return nil
}
// Decrypt decrypts from src until either EOF is reached on src or an
// error occurs. A successful Decrypt returns err == nil, not err == EOF.
func (c *Crypter) Decrypt(dst io.Writer, src io.Reader) (err error) {
keySize := c.Key.Size()
headerSize := 1 + keySize + blockSize + c.HashSize
header := make([]byte, headerSize)
if _, err = src.Read(header); err != nil {
return err
}
salt, iv, err := c.decHeader(header)
if err != nil {
return err
}
aesKey, hmacKey := c.Key.Derive(salt)
mac := hmac.New(c.HashFunc, hmacKey)
mac.Write(header[:1+keySize+blockSize])
if !bytes.Equal(header[1+keySize+blockSize:], mac.Sum(nil)) {
return errors.New("cannot authenticate header")
}
mac.Write(header[1+keySize+blockSize:])
block, err := aes.NewCipher(aesKey)
if err != nil {
return err
}
stream := cipher.NewCTR(block, iv)
buf := make([]byte, c.bufSize()+c.HashSize)
n := 0
for {
n, err = src.Read(buf)
if err != nil {
if err == io.EOF {
break
}
return err
}
stream.XORKeyStream(buf[:n-c.HashSize], buf[:n-c.HashSize])
mac.Write(buf[:n-c.HashSize])
if !bytes.Equal(buf[n-c.HashSize:n], mac.Sum(nil)) {
return errors.New("cannot authenticate packet")
}
if _, err = dst.Write(buf[:n-c.HashSize]); err != nil {
return err
}
}
return nil
}

View File

@ -1,82 +0,0 @@
package crypt
import (
"bytes"
"crypto/sha1"
"io/ioutil"
"os"
"testing"
)
var plain = [][]byte{
[]byte("Nö, ich trinke keinen Tee, ich bin Atheist. --- Helge Schneider"),
[]byte("I wish these damn scientists would leave intelligence to the experts. --- Gen. Richard Stillwell (CIA)"),
[]byte("I want to die peacefully in my sleep like my grandfather, not screaming in terror like his passengers. --- Charlie Hall"),
[]byte("NOTE 3: Each bit has the value either ZERO or ONE. --- ECMA-035 spec"),
[]byte("Writing about music is like dancing about architecture. --- Frank Zappa"),
[]byte("If you want to go somewhere, goto is the best way to get there. --- K Thompson"),
}
func TestEncryptDecrypt(t *testing.T) {
enc := bytes.NewBuffer(nil)
dec := bytes.NewBuffer(nil)
password := []byte("test password")
c := &Crypter{
HashFunc: sha1.New,
HashSize: sha1.Size,
Key: NewPbkdf2Key(password, 32),
}
defer c.Key.Reset()
for _, src := range plain {
enc.Reset()
dec.Reset()
err := c.Encrypt(enc, bytes.NewReader(src))
if err != nil {
t.Fatal(err)
}
err = c.Decrypt(dec, enc)
if err != nil {
t.Fatal(err)
}
if bytes.Compare(dec.Bytes(), src) != 0 {
t.Errorf("encrypt/decrypt error: want %q, got %q", string(src), string(dec.Bytes()))
}
}
}
func TestEncryptDecrypt1(t *testing.T) {
f, err := os.Open("crypt_test.go")
if err != nil {
t.Fatal(err)
}
defer f.Close()
encBuf := bytes.NewBuffer(nil)
password := []byte("test password")
c := &Crypter{
HashFunc: sha1.New,
HashSize: sha1.Size,
Key: NewPbkdf2Key(password, 32),
}
defer c.Key.Reset()
err = c.Encrypt(encBuf, f)
if err != nil {
t.Fatal(err)
}
decBuf := bytes.NewBuffer(nil)
err = c.Decrypt(decBuf, encBuf)
if err != nil {
t.Fatal(err)
}
src, err := ioutil.ReadFile("crypt_test.go")
if err != nil {
t.Fatal(err)
}
if bytes.Compare(decBuf.Bytes(), src) != 0 {
t.Errorf("encrypt/decrypt file error: crypt_test.go")
}
}

View File

@ -1,170 +0,0 @@
package main
import (
"bytes"
"crypto/sha1"
"flag"
"fmt"
"os"
"runtime"
"github.com/mars9/crypt"
"github.com/mars9/keyring"
"github.com/mars9/passwd"
)
var (
prompt = flag.Bool("p", false, "prompt to enter a passphrase")
decrypt = flag.Bool("d", false, "decrypt infile to oufile")
service = flag.String("s", "go-crypto", "keyring service name")
username = flag.String("u", os.Getenv("USER"), "keyring username")
initKeyring = flag.Bool("i", false, "intialize keyring")
)
func passphrase() ([]byte, error) {
if *prompt {
password, err := passwd.Get("Enter passphrase: ")
if err != nil {
return nil, fmt.Errorf("get passphrase: %v\n", err)
}
if !*decrypt {
confirm, err := passwd.Get("Confirm passphrase: ")
if err != nil {
return nil, fmt.Errorf("get passphrase: %v\n", err)
}
if !bytes.Equal(password, confirm) {
return nil, fmt.Errorf("Passphrase mismatch, try again.")
}
}
return password, nil
}
ring, err := keyring.New()
if err != nil {
return nil, err
}
return ring.Get(*service, *username)
}
func initialize() error {
password, err := passwd.Get("Enter passphrase: ")
if err != nil {
return fmt.Errorf("get passphrase: %v\n", err)
}
confirm, err := passwd.Get("Confirm passphrase: ")
if err != nil {
return fmt.Errorf("get passphrase: %v\n", err)
}
if !bytes.Equal(password, confirm) {
return fmt.Errorf("Passphrase mismatch, try again.")
}
ring, err := keyring.New()
if err != nil {
return err
}
return ring.Set(*service, *username, password)
}
func main() {
flag.Usage = usage
flag.Parse()
narg := flag.NArg()
if narg > 2 {
usage()
}
if runtime.GOOS == "windows" && narg == 0 {
usage()
}
if *initKeyring {
if err := initialize(); err != nil {
fmt.Fprintf(os.Stderr, "initialize keyring: %v", err)
os.Exit(1)
}
os.Exit(0)
}
password, err := passphrase()
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(3)
}
defer func() {
for i := range password {
password[i] = 0
}
}()
in := os.Stdin
out := os.Stdout
if narg > 0 {
in, err = os.Open(flag.Arg(0))
if err != nil {
fmt.Fprintf(os.Stderr, "open %s: %v\n", flag.Arg(0), err)
os.Exit(1)
}
defer in.Close()
if narg == 2 {
out, err = os.Create(flag.Arg(1))
if err != nil {
fmt.Fprintf(os.Stderr, "create %s: %v\n", flag.Arg(1), err)
os.Exit(1)
}
defer func() {
if err := out.Sync(); err != nil {
fmt.Fprintf(os.Stderr, "sync %s: %v\n", flag.Arg(1), err)
os.Exit(1)
}
if err := out.Close(); err != nil {
fmt.Fprintf(os.Stderr, "sync %s: %v\n", flag.Arg(1), err)
os.Exit(1)
}
}()
}
}
c := &crypt.Crypter{
HashFunc: sha1.New,
HashSize: sha1.Size,
Key: crypt.NewPbkdf2Key(password, 32),
}
if !*decrypt {
if err := c.Encrypt(out, in); err != nil {
fmt.Fprintf(os.Stderr, "encrypt: %v\n", err)
os.Exit(1)
}
} else {
if err := c.Decrypt(out, in); err != nil {
fmt.Fprintf(os.Stderr, "decrypt: %v\n", err)
os.Exit(1)
}
}
}
func usage() {
if runtime.GOOS == "windows" {
fmt.Fprintf(os.Stderr, "Usage: %s [options] infile [outfile]\n", os.Args[0])
} else {
fmt.Fprintf(os.Stderr, "Usage: %s [options] [infile] [[outfile]]\n", os.Args[0])
}
fmt.Fprint(os.Stderr, usageMsg)
fmt.Fprintf(os.Stderr, "\nOptions:\n")
flag.PrintDefaults()
os.Exit(2)
}
const usageMsg = `
Files are encrypted with AES (Rijndael) in cipher block counter mode
(CTR) and authenticate with HMAC-SHA. Encryption and HMAC keys are
derived from passphrase using PBKDF2.
If outfile is not specified, the de-/encrypted data is written to the
standard output and if infile is not specified, the de-/encrypted data
is read from standard input (reading standard input is not available
on windows).
`

79
vendor/github.com/mars9/crypt/key.go generated vendored
View File

@ -1,79 +0,0 @@
package crypt
import (
"crypto/sha1"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/scrypt"
)
// Key defines the key derivation function interface.
type Key interface {
// Derive returns the AES key and HMAC-SHA key, for the given password,
// salt combination.
Derive(salt []byte) (aesKey, hmacKey []byte)
// Size returns the key-size. Key-size should either 16, 24, or 32 to
// select AES-128, AES-192, or AES-256.
Size() int
// Reset resets/flushes the key.
Reset()
}
type pbkdf2Key struct {
password []byte
size int
}
// NewPbkdf2Key returns the key derivation function PBKDF2 as defined in
// RFC 2898.
func NewPbkdf2Key(password []byte, size int) Key {
return pbkdf2Key{password: password, size: size}
}
func (k pbkdf2Key) Derive(salt []byte) (aesKey, hmacKey []byte) {
key := pbkdf2.Key(k.password, salt, 4096, 2*k.size, sha1.New)
aesKey = key[:k.size]
hmacKey = key[k.size:]
return aesKey, hmacKey
}
func (k pbkdf2Key) Size() int { return k.size }
func (k pbkdf2Key) Reset() {
for i := range k.password {
k.password[i] = 0
}
}
type scryptKey struct {
password []byte
size int
}
// NewScryptKey returns the scrypt key derivation function as defined in
// Colin Percival's paper "Stronger Key Derivation via Sequential
// Memory-Hard Functions".
func NewScryptKey(password []byte, size int) Key {
return scryptKey{password: password, size: size}
}
func (k scryptKey) Derive(salt []byte) (aesKey, hmacKey []byte) {
key, err := scrypt.Key(k.password, salt, 16384, 8, 1, 2*k.size)
if err != nil {
panic(err)
}
aesKey = key[:k.size]
hmacKey = key[k.size:]
return aesKey, hmacKey
}
func (k scryptKey) Size() int { return k.size }
func (k scryptKey) Reset() {
for i := range k.password {
k.password[i] = 0
}
}

View File

@ -1,24 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

View File

@ -1,11 +0,0 @@
language: go
go_import_path: github.com/pkg/errors
go:
- 1.4.3
- 1.5.4
- 1.6.2
- 1.7.1
- tip
script:
- go test -v ./...

23
vendor/github.com/pkg/errors/LICENSE generated vendored
View File

@ -1,23 +0,0 @@
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,52 +0,0 @@
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors)
Package errors provides simple error handling primitives.
`go get github.com/pkg/errors`
The traditional error handling idiom in Go is roughly akin to
```go
if err != nil {
return err
}
```
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
## Adding context to an error
The errors.Wrap function returns a new error that adds context to the original error. For example
```go
_, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "read failed")
}
```
## Retrieving the cause of an error
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
```go
type causer interface {
Cause() error
}
```
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
```go
switch err := errors.Cause(err).(type) {
case *MyError:
// handle specifically
default:
// unknown error
}
```
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Contributing
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
Before proposing a change, please discuss your change by raising an issue.
## Licence
BSD-2-Clause

View File

@ -1,32 +0,0 @@
version: build-{build}.{branch}
clone_folder: C:\gopath\src\github.com\pkg\errors
shallow_clone: true # for startup speed
environment:
GOPATH: C:\gopath
platform:
- x64
# http://www.appveyor.com/docs/installed-software
install:
# some helpful output for debugging builds
- go version
- go env
# pre-installed MinGW at C:\MinGW is 32bit only
# but MSYS2 at C:\msys64 has mingw64
- set PATH=C:\msys64\mingw64\bin;%PATH%
- gcc --version
- g++ --version
build_script:
- go install -v ./...
test_script:
- set PATH=C:\gopath\bin;%PATH%
- go test -v ./...
#artifacts:
# - path: '%GOPATH%\bin\*.exe'
deploy: off

View File

@ -1,59 +0,0 @@
// +build go1.7
package errors
import (
"fmt"
"testing"
stderrors "errors"
)
func noErrors(at, depth int) error {
if at >= depth {
return stderrors.New("no error")
}
return noErrors(at+1, depth)
}
func yesErrors(at, depth int) error {
if at >= depth {
return New("ye error")
}
return yesErrors(at+1, depth)
}
func BenchmarkErrors(b *testing.B) {
var toperr error
type run struct {
stack int
std bool
}
runs := []run{
{10, false},
{10, true},
{100, false},
{100, true},
{1000, false},
{1000, true},
}
for _, r := range runs {
part := "pkg/errors"
if r.std {
part = "errors"
}
name := fmt.Sprintf("%s-stack-%d", part, r.stack)
b.Run(name, func(b *testing.B) {
var err error
f := yesErrors
if r.std {
f = noErrors
}
b.ReportAllocs()
for i := 0; i < b.N; i++ {
err = f(0, r.stack)
}
b.StopTimer()
toperr = err
})
}
}

View File

@ -1,269 +0,0 @@
// Package errors provides simple error handling primitives.
//
// The traditional error handling idiom in Go is roughly akin to
//
// if err != nil {
// return err
// }
//
// which applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
//
// Adding context to an error
//
// The errors.Wrap function returns a new error that adds context to the
// original error by recording a stack trace at the point Wrap is called,
// and the supplied message. For example
//
// _, err := ioutil.ReadAll(r)
// if err != nil {
// return errors.Wrap(err, "read failed")
// }
//
// If additional control is required the errors.WithStack and errors.WithMessage
// functions destructure errors.Wrap into its component operations of annotating
// an error with a stack trace and an a message, respectively.
//
// Retrieving the cause of an error
//
// Using errors.Wrap constructs a stack of errors, adding context to the
// preceding error. Depending on the nature of the error it may be necessary
// to reverse the operation of errors.Wrap to retrieve the original error
// for inspection. Any error value which implements this interface
//
// type causer interface {
// Cause() error
// }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error which does not implement causer, which is assumed to be
// the original cause. For example:
//
// switch err := errors.Cause(err).(type) {
// case *MyError:
// // handle specifically
// default:
// // unknown error
// }
//
// causer interface is not exported by this package, but is considered a part
// of stable public API.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported
//
// %s print the error. If the error has a Cause it will be
// printed recursively
// %v see %s
// %+v extended format. Each Frame of the error's StackTrace will
// be printed in detail.
//
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface.
//
// type stackTracer interface {
// StackTrace() errors.StackTrace
// }
//
// Where errors.StackTrace is defined as
//
// type StackTrace []Frame
//
// The Frame type represents a call site in the stack trace. Frame supports
// the fmt.Formatter interface that can be used for printing information about
// the stack trace of this error. For example:
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d", f)
// }
// }
//
// stackTracer interface is not exported by this package, but is considered a part
// of stable public API.
//
// See the documentation for Frame.Format for more details.
package errors
import (
"fmt"
"io"
)
// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(message string) error {
return &fundamental{
msg: message,
stack: callers(),
}
}
// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(format string, args ...interface{}) error {
return &fundamental{
msg: fmt.Sprintf(format, args...),
stack: callers(),
}
}
// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
msg string
*stack
}
func (f *fundamental) Error() string { return f.msg }
func (f *fundamental) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, f.msg)
f.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, f.msg)
case 'q':
fmt.Fprintf(s, "%q", f.msg)
}
}
// WithStack annotates err with a stack trace at the point WithStack was called.
// If err is nil, WithStack returns nil.
func WithStack(err error) error {
if err == nil {
return nil
}
return &withStack{
err,
callers(),
}
}
type withStack struct {
error
*stack
}
func (w *withStack) Cause() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v", w.Cause())
w.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, w.Error())
case 'q':
fmt.Fprintf(s, "%q", w.Error())
}
}
// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called, and the supplied message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: message,
}
return &withStack{
err,
callers(),
}
}
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is call, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
callers(),
}
}
// WithMessage annotates err with a new message.
// If err is nil, WithMessage returns nil.
func WithMessage(err error, message string) error {
if err == nil {
return nil
}
return &withMessage{
cause: err,
msg: message,
}
}
type withMessage struct {
cause error
msg string
}
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v\n", w.Cause())
io.WriteString(s, w.msg)
return
}
fallthrough
case 's', 'q':
io.WriteString(s, w.Error())
}
}
// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
// type causer interface {
// Cause() error
// }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
type causer interface {
Cause() error
}
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}

View File

@ -1,226 +0,0 @@
package errors
import (
"errors"
"fmt"
"io"
"reflect"
"testing"
)
func TestNew(t *testing.T) {
tests := []struct {
err string
want error
}{
{"", fmt.Errorf("")},
{"foo", fmt.Errorf("foo")},
{"foo", New("foo")},
{"string with format specifiers: %v", errors.New("string with format specifiers: %v")},
}
for _, tt := range tests {
got := New(tt.err)
if got.Error() != tt.want.Error() {
t.Errorf("New.Error(): got: %q, want %q", got, tt.want)
}
}
}
func TestWrapNil(t *testing.T) {
got := Wrap(nil, "no error")
if got != nil {
t.Errorf("Wrap(nil, \"no error\"): got %#v, expected nil", got)
}
}
func TestWrap(t *testing.T) {
tests := []struct {
err error
message string
want string
}{
{io.EOF, "read error", "read error: EOF"},
{Wrap(io.EOF, "read error"), "client error", "client error: read error: EOF"},
}
for _, tt := range tests {
got := Wrap(tt.err, tt.message).Error()
if got != tt.want {
t.Errorf("Wrap(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
}
}
}
type nilError struct{}
func (nilError) Error() string { return "nil error" }
func TestCause(t *testing.T) {
x := New("error")
tests := []struct {
err error
want error
}{{
// nil error is nil
err: nil,
want: nil,
}, {
// explicit nil error is nil
err: (error)(nil),
want: nil,
}, {
// typed nil is nil
err: (*nilError)(nil),
want: (*nilError)(nil),
}, {
// uncaused error is unaffected
err: io.EOF,
want: io.EOF,
}, {
// caused error returns cause
err: Wrap(io.EOF, "ignored"),
want: io.EOF,
}, {
err: x, // return from errors.New
want: x,
}, {
WithMessage(nil, "whoops"),
nil,
}, {
WithMessage(io.EOF, "whoops"),
io.EOF,
}, {
WithStack(nil),
nil,
}, {
WithStack(io.EOF),
io.EOF,
}}
for i, tt := range tests {
got := Cause(tt.err)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("test %d: got %#v, want %#v", i+1, got, tt.want)
}
}
}
func TestWrapfNil(t *testing.T) {
got := Wrapf(nil, "no error")
if got != nil {
t.Errorf("Wrapf(nil, \"no error\"): got %#v, expected nil", got)
}
}
func TestWrapf(t *testing.T) {
tests := []struct {
err error
message string
want string
}{
{io.EOF, "read error", "read error: EOF"},
{Wrapf(io.EOF, "read error without format specifiers"), "client error", "client error: read error without format specifiers: EOF"},
{Wrapf(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
}
for _, tt := range tests {
got := Wrapf(tt.err, tt.message).Error()
if got != tt.want {
t.Errorf("Wrapf(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
}
}
}
func TestErrorf(t *testing.T) {
tests := []struct {
err error
want string
}{
{Errorf("read error without format specifiers"), "read error without format specifiers"},
{Errorf("read error with %d format specifier", 1), "read error with 1 format specifier"},
}
for _, tt := range tests {
got := tt.err.Error()
if got != tt.want {
t.Errorf("Errorf(%v): got: %q, want %q", tt.err, got, tt.want)
}
}
}
func TestWithStackNil(t *testing.T) {
got := WithStack(nil)
if got != nil {
t.Errorf("WithStack(nil): got %#v, expected nil", got)
}
}
func TestWithStack(t *testing.T) {
tests := []struct {
err error
want string
}{
{io.EOF, "EOF"},
{WithStack(io.EOF), "EOF"},
}
for _, tt := range tests {
got := WithStack(tt.err).Error()
if got != tt.want {
t.Errorf("WithStack(%v): got: %v, want %v", tt.err, got, tt.want)
}
}
}
func TestWithMessageNil(t *testing.T) {
got := WithMessage(nil, "no error")
if got != nil {
t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got)
}
}
func TestWithMessage(t *testing.T) {
tests := []struct {
err error
message string
want string
}{
{io.EOF, "read error", "read error: EOF"},
{WithMessage(io.EOF, "read error"), "client error", "client error: read error: EOF"},
}
for _, tt := range tests {
got := WithMessage(tt.err, tt.message).Error()
if got != tt.want {
t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
}
}
}
// errors.New, etc values are not expected to be compared by value
// but the change in errors#27 made them incomparable. Assert that
// various kinds of errors have a functional equality operator, even
// if the result of that equality is always false.
func TestErrorEquality(t *testing.T) {
vals := []error{
nil,
io.EOF,
errors.New("EOF"),
New("EOF"),
Errorf("EOF"),
Wrap(io.EOF, "EOF"),
Wrapf(io.EOF, "EOF%d", 2),
WithMessage(nil, "whoops"),
WithMessage(io.EOF, "whoops"),
WithStack(io.EOF),
WithStack(nil),
}
for i := range vals {
for j := range vals {
_ = vals[i] == vals[j] // mustn't panic
}
}
}

View File

@ -1,205 +0,0 @@
package errors_test
import (
"fmt"
"github.com/pkg/errors"
)
func ExampleNew() {
err := errors.New("whoops")
fmt.Println(err)
// Output: whoops
}
func ExampleNew_printf() {
err := errors.New("whoops")
fmt.Printf("%+v", err)
// Example output:
// whoops
// github.com/pkg/errors_test.ExampleNew_printf
// /home/dfc/src/github.com/pkg/errors/example_test.go:17
// testing.runExample
// /home/dfc/go/src/testing/example.go:114
// testing.RunExamples
// /home/dfc/go/src/testing/example.go:38
// testing.(*M).Run
// /home/dfc/go/src/testing/testing.go:744
// main.main
// /github.com/pkg/errors/_test/_testmain.go:106
// runtime.main
// /home/dfc/go/src/runtime/proc.go:183
// runtime.goexit
// /home/dfc/go/src/runtime/asm_amd64.s:2059
}
func ExampleWithMessage() {
cause := errors.New("whoops")
err := errors.WithMessage(cause, "oh noes")
fmt.Println(err)
// Output: oh noes: whoops
}
func ExampleWithStack() {
cause := errors.New("whoops")
err := errors.WithStack(cause)
fmt.Println(err)
// Output: whoops
}
func ExampleWithStack_printf() {
cause := errors.New("whoops")
err := errors.WithStack(cause)
fmt.Printf("%+v", err)
// Example Output:
// whoops
// github.com/pkg/errors_test.ExampleWithStack_printf
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:55
// testing.runExample
// /usr/lib/go/src/testing/example.go:114
// testing.RunExamples
// /usr/lib/go/src/testing/example.go:38
// testing.(*M).Run
// /usr/lib/go/src/testing/testing.go:744
// main.main
// github.com/pkg/errors/_test/_testmain.go:106
// runtime.main
// /usr/lib/go/src/runtime/proc.go:183
// runtime.goexit
// /usr/lib/go/src/runtime/asm_amd64.s:2086
// github.com/pkg/errors_test.ExampleWithStack_printf
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:56
// testing.runExample
// /usr/lib/go/src/testing/example.go:114
// testing.RunExamples
// /usr/lib/go/src/testing/example.go:38
// testing.(*M).Run
// /usr/lib/go/src/testing/testing.go:744
// main.main
// github.com/pkg/errors/_test/_testmain.go:106
// runtime.main
// /usr/lib/go/src/runtime/proc.go:183
// runtime.goexit
// /usr/lib/go/src/runtime/asm_amd64.s:2086
}
func ExampleWrap() {
cause := errors.New("whoops")
err := errors.Wrap(cause, "oh noes")
fmt.Println(err)
// Output: oh noes: whoops
}
func fn() error {
e1 := errors.New("error")
e2 := errors.Wrap(e1, "inner")
e3 := errors.Wrap(e2, "middle")
return errors.Wrap(e3, "outer")
}
func ExampleCause() {
err := fn()
fmt.Println(err)
fmt.Println(errors.Cause(err))
// Output: outer: middle: inner: error
// error
}
func ExampleWrap_extended() {
err := fn()
fmt.Printf("%+v\n", err)
// Example output:
// error
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:47
// github.com/pkg/errors_test.ExampleCause_printf
// /home/dfc/src/github.com/pkg/errors/example_test.go:63
// testing.runExample
// /home/dfc/go/src/testing/example.go:114
// testing.RunExamples
// /home/dfc/go/src/testing/example.go:38
// testing.(*M).Run
// /home/dfc/go/src/testing/testing.go:744
// main.main
// /github.com/pkg/errors/_test/_testmain.go:104
// runtime.main
// /home/dfc/go/src/runtime/proc.go:183
// runtime.goexit
// /home/dfc/go/src/runtime/asm_amd64.s:2059
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:48: inner
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:49: middle
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:50: outer
}
func ExampleWrapf() {
cause := errors.New("whoops")
err := errors.Wrapf(cause, "oh noes #%d", 2)
fmt.Println(err)
// Output: oh noes #2: whoops
}
func ExampleErrorf_extended() {
err := errors.Errorf("whoops: %s", "foo")
fmt.Printf("%+v", err)
// Example output:
// whoops: foo
// github.com/pkg/errors_test.ExampleErrorf
// /home/dfc/src/github.com/pkg/errors/example_test.go:101
// testing.runExample
// /home/dfc/go/src/testing/example.go:114
// testing.RunExamples
// /home/dfc/go/src/testing/example.go:38
// testing.(*M).Run
// /home/dfc/go/src/testing/testing.go:744
// main.main
// /github.com/pkg/errors/_test/_testmain.go:102
// runtime.main
// /home/dfc/go/src/runtime/proc.go:183
// runtime.goexit
// /home/dfc/go/src/runtime/asm_amd64.s:2059
}
func Example_stackTrace() {
type stackTracer interface {
StackTrace() errors.StackTrace
}
err, ok := errors.Cause(fn()).(stackTracer)
if !ok {
panic("oops, err does not implement stackTracer")
}
st := err.StackTrace()
fmt.Printf("%+v", st[0:2]) // top two frames
// Example output:
// github.com/pkg/errors_test.fn
// /home/dfc/src/github.com/pkg/errors/example_test.go:47
// github.com/pkg/errors_test.Example_stackTrace
// /home/dfc/src/github.com/pkg/errors/example_test.go:127
}
func ExampleCause_printf() {
err := errors.Wrap(func() error {
return func() error {
return errors.Errorf("hello %s", fmt.Sprintf("world"))
}()
}(), "failed")
fmt.Printf("%v", err)
// Output: failed: hello world
}

View File

@ -1,535 +0,0 @@
package errors
import (
"errors"
"fmt"
"io"
"regexp"
"strings"
"testing"
)
func TestFormatNew(t *testing.T) {
tests := []struct {
error
format string
want string
}{{
New("error"),
"%s",
"error",
}, {
New("error"),
"%v",
"error",
}, {
New("error"),
"%+v",
"error\n" +
"github.com/pkg/errors.TestFormatNew\n" +
"\t.+/github.com/pkg/errors/format_test.go:26",
}, {
New("error"),
"%q",
`"error"`,
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
}
}
func TestFormatErrorf(t *testing.T) {
tests := []struct {
error
format string
want string
}{{
Errorf("%s", "error"),
"%s",
"error",
}, {
Errorf("%s", "error"),
"%v",
"error",
}, {
Errorf("%s", "error"),
"%+v",
"error\n" +
"github.com/pkg/errors.TestFormatErrorf\n" +
"\t.+/github.com/pkg/errors/format_test.go:56",
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
}
}
func TestFormatWrap(t *testing.T) {
tests := []struct {
error
format string
want string
}{{
Wrap(New("error"), "error2"),
"%s",
"error2: error",
}, {
Wrap(New("error"), "error2"),
"%v",
"error2: error",
}, {
Wrap(New("error"), "error2"),
"%+v",
"error\n" +
"github.com/pkg/errors.TestFormatWrap\n" +
"\t.+/github.com/pkg/errors/format_test.go:82",
}, {
Wrap(io.EOF, "error"),
"%s",
"error: EOF",
}, {
Wrap(io.EOF, "error"),
"%v",
"error: EOF",
}, {
Wrap(io.EOF, "error"),
"%+v",
"EOF\n" +
"error\n" +
"github.com/pkg/errors.TestFormatWrap\n" +
"\t.+/github.com/pkg/errors/format_test.go:96",
}, {
Wrap(Wrap(io.EOF, "error1"), "error2"),
"%+v",
"EOF\n" +
"error1\n" +
"github.com/pkg/errors.TestFormatWrap\n" +
"\t.+/github.com/pkg/errors/format_test.go:103\n",
}, {
Wrap(New("error with space"), "context"),
"%q",
`"context: error with space"`,
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
}
}
func TestFormatWrapf(t *testing.T) {
tests := []struct {
error
format string
want string
}{{
Wrapf(io.EOF, "error%d", 2),
"%s",
"error2: EOF",
}, {
Wrapf(io.EOF, "error%d", 2),
"%v",
"error2: EOF",
}, {
Wrapf(io.EOF, "error%d", 2),
"%+v",
"EOF\n" +
"error2\n" +
"github.com/pkg/errors.TestFormatWrapf\n" +
"\t.+/github.com/pkg/errors/format_test.go:134",
}, {
Wrapf(New("error"), "error%d", 2),
"%s",
"error2: error",
}, {
Wrapf(New("error"), "error%d", 2),
"%v",
"error2: error",
}, {
Wrapf(New("error"), "error%d", 2),
"%+v",
"error\n" +
"github.com/pkg/errors.TestFormatWrapf\n" +
"\t.+/github.com/pkg/errors/format_test.go:149",
}}
for i, tt := range tests {
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
}
}
func TestFormatWithStack(t *testing.T) {
tests := []struct {
error
format string
want []string
}{{
WithStack(io.EOF),
"%s",
[]string{"EOF"},
}, {
WithStack(io.EOF),
"%v",
[]string{"EOF"},
}, {
WithStack(io.EOF),
"%+v",
[]string{"EOF",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:175"},
}, {
WithStack(New("error")),
"%s",
[]string{"error"},
}, {
WithStack(New("error")),
"%v",
[]string{"error"},
}, {
WithStack(New("error")),
"%+v",
[]string{"error",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:189",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:189"},
}, {
WithStack(WithStack(io.EOF)),
"%+v",
[]string{"EOF",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:197",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:197"},
}, {
WithStack(WithStack(Wrapf(io.EOF, "message"))),
"%+v",
[]string{"EOF",
"message",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:205",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:205",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:205"},
}, {
WithStack(Errorf("error%d", 1)),
"%+v",
[]string{"error1",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:216",
"github.com/pkg/errors.TestFormatWithStack\n" +
"\t.+/github.com/pkg/errors/format_test.go:216"},
}}
for i, tt := range tests {
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
}
}
func TestFormatWithMessage(t *testing.T) {
tests := []struct {
error
format string
want []string
}{{
WithMessage(New("error"), "error2"),
"%s",
[]string{"error2: error"},
}, {
WithMessage(New("error"), "error2"),
"%v",
[]string{"error2: error"},
}, {
WithMessage(New("error"), "error2"),
"%+v",
[]string{
"error",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:244",
"error2"},
}, {
WithMessage(io.EOF, "addition1"),
"%s",
[]string{"addition1: EOF"},
}, {
WithMessage(io.EOF, "addition1"),
"%v",
[]string{"addition1: EOF"},
}, {
WithMessage(io.EOF, "addition1"),
"%+v",
[]string{"EOF", "addition1"},
}, {
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
"%v",
[]string{"addition2: addition1: EOF"},
}, {
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
"%+v",
[]string{"EOF", "addition1", "addition2"},
}, {
Wrap(WithMessage(io.EOF, "error1"), "error2"),
"%+v",
[]string{"EOF", "error1", "error2",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:272"},
}, {
WithMessage(Errorf("error%d", 1), "error2"),
"%+v",
[]string{"error1",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:278",
"error2"},
}, {
WithMessage(WithStack(io.EOF), "error"),
"%+v",
[]string{
"EOF",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:285",
"error"},
}, {
WithMessage(Wrap(WithStack(io.EOF), "inside-error"), "outside-error"),
"%+v",
[]string{
"EOF",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:293",
"inside-error",
"github.com/pkg/errors.TestFormatWithMessage\n" +
"\t.+/github.com/pkg/errors/format_test.go:293",
"outside-error"},
}}
for i, tt := range tests {
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
}
}
func TestFormatGeneric(t *testing.T) {
starts := []struct {
err error
want []string
}{
{New("new-error"), []string{
"new-error",
"github.com/pkg/errors.TestFormatGeneric\n" +
"\t.+/github.com/pkg/errors/format_test.go:315"},
}, {Errorf("errorf-error"), []string{
"errorf-error",
"github.com/pkg/errors.TestFormatGeneric\n" +
"\t.+/github.com/pkg/errors/format_test.go:319"},
}, {errors.New("errors-new-error"), []string{
"errors-new-error"},
},
}
wrappers := []wrapper{
{
func(err error) error { return WithMessage(err, "with-message") },
[]string{"with-message"},
}, {
func(err error) error { return WithStack(err) },
[]string{
"github.com/pkg/errors.(func·002|TestFormatGeneric.func2)\n\t" +
".+/github.com/pkg/errors/format_test.go:333",
},
}, {
func(err error) error { return Wrap(err, "wrap-error") },
[]string{
"wrap-error",
"github.com/pkg/errors.(func·003|TestFormatGeneric.func3)\n\t" +
".+/github.com/pkg/errors/format_test.go:339",
},
}, {
func(err error) error { return Wrapf(err, "wrapf-error%d", 1) },
[]string{
"wrapf-error1",
"github.com/pkg/errors.(func·004|TestFormatGeneric.func4)\n\t" +
".+/github.com/pkg/errors/format_test.go:346",
},
},
}
for s := range starts {
err := starts[s].err
want := starts[s].want
testFormatCompleteCompare(t, s, err, "%+v", want, false)
testGenericRecursive(t, err, want, wrappers, 3)
}
}
func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) {
got := fmt.Sprintf(format, arg)
gotLines := strings.SplitN(got, "\n", -1)
wantLines := strings.SplitN(want, "\n", -1)
if len(wantLines) > len(gotLines) {
t.Errorf("test %d: wantLines(%d) > gotLines(%d):\n got: %q\nwant: %q", n+1, len(wantLines), len(gotLines), got, want)
return
}
for i, w := range wantLines {
match, err := regexp.MatchString(w, gotLines[i])
if err != nil {
t.Fatal(err)
}
if !match {
t.Errorf("test %d: line %d: fmt.Sprintf(%q, err):\n got: %q\nwant: %q", n+1, i+1, format, got, want)
}
}
}
var stackLineR = regexp.MustCompile(`\.`)
// parseBlocks parses input into a slice, where:
// - incase entry contains a newline, its a stacktrace
// - incase entry contains no newline, its a solo line.
//
// Detecting stack boundaries only works incase the WithStack-calls are
// to be found on the same line, thats why it is optionally here.
//
// Example use:
//
// for _, e := range blocks {
// if strings.ContainsAny(e, "\n") {
// // Match as stack
// } else {
// // Match as line
// }
// }
//
func parseBlocks(input string, detectStackboundaries bool) ([]string, error) {
var blocks []string
stack := ""
wasStack := false
lines := map[string]bool{} // already found lines
for _, l := range strings.Split(input, "\n") {
isStackLine := stackLineR.MatchString(l)
switch {
case !isStackLine && wasStack:
blocks = append(blocks, stack, l)
stack = ""
lines = map[string]bool{}
case isStackLine:
if wasStack {
// Detecting two stacks after another, possible cause lines match in
// our tests due to WithStack(WithStack(io.EOF)) on same line.
if detectStackboundaries {
if lines[l] {
if len(stack) == 0 {
return nil, errors.New("len of block must not be zero here")
}
blocks = append(blocks, stack)
stack = l
lines = map[string]bool{l: true}
continue
}
}
stack = stack + "\n" + l
} else {
stack = l
}
lines[l] = true
case !isStackLine && !wasStack:
blocks = append(blocks, l)
default:
return nil, errors.New("must not happen")
}
wasStack = isStackLine
}
// Use up stack
if stack != "" {
blocks = append(blocks, stack)
}
return blocks, nil
}
func testFormatCompleteCompare(t *testing.T, n int, arg interface{}, format string, want []string, detectStackBoundaries bool) {
gotStr := fmt.Sprintf(format, arg)
got, err := parseBlocks(gotStr, detectStackBoundaries)
if err != nil {
t.Fatal(err)
}
if len(got) != len(want) {
t.Fatalf("test %d: fmt.Sprintf(%s, err) -> wrong number of blocks: got(%d) want(%d)\n got: %s\nwant: %s\ngotStr: %q",
n+1, format, len(got), len(want), prettyBlocks(got), prettyBlocks(want), gotStr)
}
for i := range got {
if strings.ContainsAny(want[i], "\n") {
// Match as stack
match, err := regexp.MatchString(want[i], got[i])
if err != nil {
t.Fatal(err)
}
if !match {
t.Fatalf("test %d: block %d: fmt.Sprintf(%q, err):\ngot:\n%q\nwant:\n%q\nall-got:\n%s\nall-want:\n%s\n",
n+1, i+1, format, got[i], want[i], prettyBlocks(got), prettyBlocks(want))
}
} else {
// Match as message
if got[i] != want[i] {
t.Fatalf("test %d: fmt.Sprintf(%s, err) at block %d got != want:\n got: %q\nwant: %q", n+1, format, i+1, got[i], want[i])
}
}
}
}
type wrapper struct {
wrap func(err error) error
want []string
}
func prettyBlocks(blocks []string, prefix ...string) string {
var out []string
for _, b := range blocks {
out = append(out, fmt.Sprintf("%v", b))
}
return " " + strings.Join(out, "\n ")
}
func testGenericRecursive(t *testing.T, beforeErr error, beforeWant []string, list []wrapper, maxDepth int) {
if len(beforeWant) == 0 {
panic("beforeWant must not be empty")
}
for _, w := range list {
if len(w.want) == 0 {
panic("want must not be empty")
}
err := w.wrap(beforeErr)
// Copy required cause append(beforeWant, ..) modified beforeWant subtly.
beforeCopy := make([]string, len(beforeWant))
copy(beforeCopy, beforeWant)
beforeWant := beforeCopy
last := len(beforeWant) - 1
var want []string
// Merge two stacks behind each other.
if strings.ContainsAny(beforeWant[last], "\n") && strings.ContainsAny(w.want[0], "\n") {
want = append(beforeWant[:last], append([]string{beforeWant[last] + "((?s).*)" + w.want[0]}, w.want[1:]...)...)
} else {
want = append(beforeWant, w.want...)
}
testFormatCompleteCompare(t, maxDepth, err, "%+v", want, false)
if maxDepth > 0 {
testGenericRecursive(t, err, want, list, maxDepth-1)
}
}
}

178
vendor/github.com/pkg/errors/stack.go generated vendored
View File

@ -1,178 +0,0 @@
package errors
import (
"fmt"
"io"
"path"
"runtime"
"strings"
)
// Frame represents a program counter inside a stack frame.
type Frame uintptr
// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
// file returns the full path to the file that contains the
// function for this Frame's pc.
func (f Frame) file() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
file, _ := fn.FileLine(f.pc())
return file
}
// line returns the line number of source code of the
// function for this Frame's pc.
func (f Frame) line() int {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return 0
}
_, line := fn.FileLine(f.pc())
return line
}
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
// %d source line
// %n function name
// %v equivalent to %s:%d
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+s path of source file relative to the compile time GOPATH
// %+v equivalent to %+s:%d
func (f Frame) Format(s fmt.State, verb rune) {
switch verb {
case 's':
switch {
case s.Flag('+'):
pc := f.pc()
fn := runtime.FuncForPC(pc)
if fn == nil {
io.WriteString(s, "unknown")
} else {
file, _ := fn.FileLine(pc)
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
}
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
fmt.Fprintf(s, "%d", f.line())
case 'n':
name := runtime.FuncForPC(f.pc()).Name()
io.WriteString(s, funcname(name))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
f.Format(s, 'd')
}
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
for _, f := range st {
fmt.Fprintf(s, "\n%+v", f)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
fmt.Fprintf(s, "%v", []Frame(st))
}
case 's':
fmt.Fprintf(s, "%s", []Frame(st))
}
}
// stack represents a stack of program counters.
type stack []uintptr
func (s *stack) Format(st fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case st.Flag('+'):
for _, pc := range *s {
f := Frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}
func (s *stack) StackTrace() StackTrace {
f := make([]Frame, len(*s))
for i := 0; i < len(f); i++ {
f[i] = Frame((*s)[i])
}
return f
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st stack = pcs[0:n]
return &st
}
// funcname removes the path prefix component of a function's name reported by func.Name().
func funcname(name string) string {
i := strings.LastIndex(name, "/")
name = name[i+1:]
i = strings.Index(name, ".")
return name[i+1:]
}
func trimGOPATH(name, file string) string {
// Here we want to get the source file path relative to the compile time
// GOPATH. As of Go 1.6.x there is no direct way to know the compiled
// GOPATH at runtime, but we can infer the number of path segments in the
// GOPATH. We note that fn.Name() returns the function name qualified by
// the import path, which does not include the GOPATH. Thus we can trim
// segments from the beginning of the file path until the number of path
// separators remaining is one more than the number of path separators in
// the function name. For example, given:
//
// GOPATH /home/user
// file /home/user/src/pkg/sub/file.go
// fn.Name() pkg/sub.Type.Method
//
// We want to produce:
//
// pkg/sub/file.go
//
// From this we can easily see that fn.Name() has one less path separator
// than our desired output. We count separators from the end of the file
// path until it finds two more than in the function name and then move
// one character forward to preserve the initial path segment without a
// leading separator.
const sep = "/"
goal := strings.Count(name, sep) + 2
i := len(file)
for n := 0; n < goal; n++ {
i = strings.LastIndex(file[:i], sep)
if i == -1 {
// not enough separators found, set i so that the slice expression
// below leaves file unmodified
i = -len(sep)
break
}
}
// get back to 0 or trim the leading separator
file = file[i+len(sep):]
return file
}

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