Compare commits
No commits in common. "main" and "issue598" have entirely different histories.
|
|
@ -1,9 +1,41 @@
|
||||||
---
|
---
|
||||||
name: New issue
|
name: Bug report
|
||||||
about: Create an issue
|
about: Create a report to help us improve
|
||||||
title: ''
|
title: ''
|
||||||
|
labels: bug
|
||||||
assignees: ''
|
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
|
||||||
|
<-- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
|
|
||||||
|
## To Reproduce
|
||||||
|
Steps to reproduce the behavior:
|
||||||
|
<-- 1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error -->
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
4.
|
||||||
|
|
||||||
|
## Expected behaviour
|
||||||
|
<-- A clear and concise description of what you expected to happen. -->
|
||||||
|
|
||||||
|
|
||||||
|
## Version
|
||||||
|
<-- Check "croc -v" and report it -->
|
||||||
|
|
||||||
|
|
||||||
|
## Additional context
|
||||||
|
<-- Add any other context about the problem here. -->
|
||||||
|
|
||||||
|
|
||||||
*Read this and delete before submitting:* Thanks for starting a discussion! Please provide as much context as possible so that others can understand your thoughts. If you have a specific change in mind, consider submitting a pull request instead.
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -13,40 +13,6 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-go@v5
|
- uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.20'
|
||||||
- run: go version
|
- run: go version
|
||||||
- run: go test -v ./...
|
- run: go test -v ./...
|
||||||
- name: Build files
|
|
||||||
run: |
|
|
||||||
go version
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags '-extldflags "-static"' -o croc.exe
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags '-extldflags "-static"' -o croc.exe
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=arm go build -ldflags '-extldflags "-static"' -o croc.exe
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -ldflags '-extldflags "-static"' -o croc.exe
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags '-extldflags "-static"' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags '-extldflags "-static"' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags '-extldflags "-static"' -o croc
|
|
||||||
GOARM=5 CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags '-extldflags "-static"' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags '-extldflags "-static"' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags '-s -extldflags "-sectcreate __TEXT __info_plist Info.plist"' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags '-s -extldflags "-sectcreate __TEXT __info_plist Info.plist"' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=dragonfly GOARCH=amd64 go build -ldflags '' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags '' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags '' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=netbsd GOARCH=386 go build -ldflags '' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=netbsd GOARCH=amd64 go build -ldflags '' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=netbsd GOARCH=arm64 go build -ldflags '' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 go build -ldflags '' -o croc
|
|
||||||
CGO_ENABLED=0 GOOS=openbsd GOARCH=arm64 go build -ldflags '' -o croc
|
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.20.7' # go1.20.8+ refuses to build go1.22 code...
|
|
||||||
- name: Build Windows 7
|
|
||||||
run: |
|
|
||||||
go version
|
|
||||||
rm go.mod go.sum
|
|
||||||
go mod init github.com/schollz/croc/v10
|
|
||||||
go mod tidy
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags '-extldflags "-static"' -o croc.exe
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags '-extldflags "-static"' -o croc.exe
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ jobs:
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
-
|
-
|
||||||
name: Build and push
|
name: Build and push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,17 @@ jobs:
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v4
|
uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
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
|
- name: Prepare source tarball
|
||||||
run: |
|
run: |
|
||||||
git clone -b ${{ github.event.release.name }} --depth 1 https://github.com/schollz/croc croc-${{ github.event.release.name }}
|
git clone -b ${{ github.event.release.name }} --depth 1 https://github.com/schollz/croc croc-${{ github.event.release.name }}
|
||||||
|
|
@ -39,8 +49,6 @@ jobs:
|
||||||
tar -czvf croc_${{ github.event.release.name }}_Linux-32bit.tar.gz croc LICENSE
|
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
|
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
|
tar -czvf croc_${{ github.event.release.name }}_Linux-ARM.tar.gz croc LICENSE
|
||||||
GOARM=5 CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags '-extldflags "-static"' -o croc
|
|
||||||
tar -czvf croc_${{ github.event.release.name }}_Linux-ARMv5.tar.gz croc LICENSE
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags '-extldflags "-static"' -o croc
|
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
|
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
|
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags '-s -extldflags "-sectcreate __TEXT __info_plist Info.plist"' -o croc
|
||||||
|
|
@ -63,20 +71,6 @@ jobs:
|
||||||
tar -czvf croc_${{ github.event.release.name }}_OpenBSD-64bit.tar.gz croc LICENSE
|
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
|
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
|
tar -czvf croc_${{ github.event.release.name }}_OpenBSD-ARM64.tar.gz croc LICENSE
|
||||||
- name: Setup Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.20.7' # go1.20.8+ refuses to build go1.22 code...
|
|
||||||
- name: Build Windows 7
|
|
||||||
run: |
|
|
||||||
go version
|
|
||||||
rm go.mod go.sum
|
|
||||||
go mod init github.com/schollz/croc/v10
|
|
||||||
go mod tidy
|
|
||||||
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: Create checksums.txt
|
- name: Create checksums.txt
|
||||||
run: |
|
run: |
|
||||||
touch croc_${{ github.event.release.name }}_checksums.txt
|
touch croc_${{ github.event.release.name }}_checksums.txt
|
||||||
|
|
@ -90,7 +84,6 @@ jobs:
|
||||||
sha256sum croc_${{ github.event.release.name }}_Linux-64bit.tar.gz >> 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-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-ARM.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||||
sha256sum croc_${{ github.event.release.name }}_Linux-ARMv5.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 }}_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-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 }}_macOS-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||||
|
|
@ -117,7 +110,6 @@ jobs:
|
||||||
croc_${{ github.event.release.name }}_Linux-64bit.tar.gz
|
croc_${{ github.event.release.name }}_Linux-64bit.tar.gz
|
||||||
croc_${{ github.event.release.name }}_Linux-32bit.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-ARM.tar.gz
|
||||||
croc_${{ github.event.release.name }}_Linux-ARMv5.tar.gz
|
|
||||||
croc_${{ github.event.release.name }}_Linux-ARM64.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-64bit.tar.gz
|
||||||
croc_${{ github.event.release.name }}_macOS-ARM64.tar.gz
|
croc_${{ github.event.release.name }}_macOS-ARM64.tar.gz
|
||||||
|
|
|
||||||
12
.travis.yml
12
.travis.yml
|
|
@ -10,12 +10,12 @@ install: true
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- env GO111MODULE=on go build -v
|
- env GO111MODULE=on go build -v
|
||||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/compress
|
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/compress
|
||||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/croc
|
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/croc
|
||||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/crypt
|
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/crypt
|
||||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/tcp
|
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/tcp
|
||||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/utils
|
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/utils
|
||||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/comm
|
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/comm
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
except:
|
except:
|
||||||
|
|
|
||||||
40
README.md
40
README.md
|
|
@ -4,9 +4,10 @@
|
||||||
src="https://user-images.githubusercontent.com/6550035/46709024-9b23ad00-cbf6-11e8-9fb2-ca8b20b7dbec.jpg"
|
src="https://user-images.githubusercontent.com/6550035/46709024-9b23ad00-cbf6-11e8-9fb2-ca8b20b7dbec.jpg"
|
||||||
width="408px" border="0" alt="croc">
|
width="408px" border="0" alt="croc">
|
||||||
<br>
|
<br>
|
||||||
<a href="https://github.com/schollz/croc/releases/latest"><img src="https://img.shields.io/badge/version-v10.1.1-brightgreen.svg?style=flat-square" alt="Version"></a>
|
<a href="https://github.com/schollz/croc/releases/latest"><img src="https://img.shields.io/badge/version-v9.6.15-brightgreen.svg?style=flat-square" alt="Version"></a>
|
||||||
<a href="https://github.com/schollz/croc/actions/workflows/ci.yml"><img
|
<a href="https://coveralls.io/github/schollz/croc"><img src="https://img.shields.io/badge/coverage-81%25-green.svg?style=flat-square" alt="Coverage"></a>
|
||||||
src="https://github.com/schollz/croc/actions/workflows/ci.yml/badge.svg" alt="Build
|
<a href="https://travis-ci.org/schollz/croc"><img
|
||||||
|
src="https://img.shields.io/travis/schollz/croc.svg?style=flat-square" alt="Build
|
||||||
Status"></a>
|
Status"></a>
|
||||||
<p align="center">This project is supported by <a href="https://github.com/sponsors/schollz">Github sponsors</a>.</p>
|
<p align="center">This project is supported by <a href="https://github.com/sponsors/schollz">Github sponsors</a>.</p>
|
||||||
|
|
||||||
|
|
@ -104,22 +105,10 @@ On FreeBSD you can install with `pkg`:
|
||||||
pkg install croc
|
pkg install croc
|
||||||
```
|
```
|
||||||
|
|
||||||
On Linux, macOS, and Windows you can install from [conda-forge](https://github.com/conda-forge/croc-feedstock/) globally with [`pixi`](https://pixi.sh/):
|
|
||||||
|
|
||||||
```
|
|
||||||
pixi global install croc
|
|
||||||
```
|
|
||||||
|
|
||||||
or into a particular environment with [`conda`](https://docs.conda.io/projects/conda/):
|
|
||||||
|
|
||||||
```
|
|
||||||
conda install --channel conda-forge croc
|
|
||||||
```
|
|
||||||
|
|
||||||
Or, you can [install Go](https://golang.org/dl/) and build from source (requires Go 1.17+):
|
Or, you can [install Go](https://golang.org/dl/) and build from source (requires Go 1.17+):
|
||||||
|
|
||||||
```
|
```
|
||||||
go install github.com/schollz/croc/v10@latest
|
go install github.com/schollz/croc/v9@latest
|
||||||
```
|
```
|
||||||
|
|
||||||
On Android there is a 3rd party F-Droid app [available to download](https://f-droid.org/en/packages/com.github.howeyc.crocgui/).
|
On Android there is a 3rd party F-Droid app [available to download](https://f-droid.org/en/packages/com.github.howeyc.crocgui/).
|
||||||
|
|
@ -145,25 +134,6 @@ The code phrase is used to establish password-authenticated key agreement ([PAKE
|
||||||
|
|
||||||
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`.
|
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`.
|
||||||
|
|
||||||
### Using `croc` on Linux or Mac OS
|
|
||||||
|
|
||||||
On Linux and Mac OS, the sending & receiving is slightly different to avoid [leaking the secret via the process name](https://nvd.nist.gov/vuln/detail/CVE-2023-43621). On these systems you will need to run `croc` with the secret as an environment variable. For example, to receive with the secret `***`:
|
|
||||||
|
|
||||||
```
|
|
||||||
CROC_SECRET=*** croc
|
|
||||||
```
|
|
||||||
|
|
||||||
This will show only `croc` in the process list of a multi-user system and not leak the secret.
|
|
||||||
|
|
||||||
For a single-user system the default behavior can be permanently enabled by running
|
|
||||||
|
|
||||||
```
|
|
||||||
croc --classic
|
|
||||||
```
|
|
||||||
|
|
||||||
and confirming.
|
|
||||||
Run this command again to disable classic mode.
|
|
||||||
|
|
||||||
### Custom code phrase
|
### Custom code phrase
|
||||||
|
|
||||||
You can send with your own code phrase (must be more than 6 characters).
|
You can send with your own code phrase (must be more than 6 characters).
|
||||||
|
|
|
||||||
33
go.mod
33
go.mod
|
|
@ -1,39 +1,40 @@
|
||||||
module github.com/schollz/croc/v10
|
module github.com/schollz/croc/v9
|
||||||
|
|
||||||
go 1.22
|
go 1.20
|
||||||
|
|
||||||
toolchain go1.23.1
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cespare/xxhash v1.1.0
|
github.com/cespare/xxhash v1.1.0
|
||||||
github.com/chzyer/readline v1.5.1
|
github.com/chzyer/readline v1.5.1
|
||||||
github.com/denisbrodbeck/machineid v1.0.1
|
github.com/denisbrodbeck/machineid v1.0.1
|
||||||
github.com/kalafut/imohash v1.1.0
|
github.com/kalafut/imohash v1.0.3
|
||||||
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b
|
|
||||||
github.com/minio/highwayhash v1.0.3
|
|
||||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
|
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
|
||||||
github.com/schollz/cli/v2 v2.2.1
|
github.com/schollz/cli/v2 v2.2.1
|
||||||
github.com/schollz/logger v1.2.0
|
github.com/schollz/logger v1.2.0
|
||||||
|
github.com/schollz/mnemonicode v1.0.2-0.20190421205639-63fa713ece0d
|
||||||
github.com/schollz/pake/v3 v3.0.5
|
github.com/schollz/pake/v3 v3.0.5
|
||||||
github.com/schollz/peerdiscovery v1.7.5
|
github.com/schollz/peerdiscovery v1.7.3
|
||||||
github.com/schollz/progressbar/v3 v3.17.1
|
github.com/schollz/progressbar/v3 v3.14.3
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
golang.org/x/crypto v0.29.0
|
golang.org/x/crypto v0.23.0
|
||||||
golang.org/x/net v0.31.0
|
golang.org/x/net v0.25.0
|
||||||
golang.org/x/sys v0.27.0
|
golang.org/x/time v0.5.0
|
||||||
golang.org/x/term v0.26.0
|
|
||||||
golang.org/x/time v0.8.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
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/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/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rivo/uniseg v0.4.7 // indirect
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // 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/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406 // indirect
|
||||||
github.com/twmb/murmur3 v1.1.8 // indirect
|
github.com/twmb/murmur3 v1.1.8 // indirect
|
||||||
|
golang.org/x/sys v0.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
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
83
go.sum
83
go.sum
|
|
@ -1,10 +1,9 @@
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
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 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM=
|
|
||||||
github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY=
|
|
||||||
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
|
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
|
||||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
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 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||||
|
|
@ -12,22 +11,24 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk
|
||||||
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
|
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
|
||||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
|
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
|
||||||
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
|
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||||
github.com/kalafut/imohash v1.1.0 h1:Lldcmx0SXgMSoABB2WBD8mTgf0OlVnISn2Dyrfg2Ep8=
|
github.com/kalafut/imohash v1.0.3 h1:p9c61km8+6ZMqKRnERwdoxp/CztrdLNEbpsyGgf+A4M=
|
||||||
github.com/kalafut/imohash v1.1.0/go.mod h1:6cn9lU0Sj8M4eu9UaQm1kR/5y3k/ayB68yntRhGloL4=
|
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 h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI=
|
||||||
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
|
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
|
||||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
|
||||||
github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
|
|
||||||
github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
|
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
|
@ -43,18 +44,20 @@ 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/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 h1:5WXfINRs3lEUTCZ7YXhj0uN+qukjizvITLm3Ca2m0Ho=
|
||||||
github.com/schollz/logger v1.2.0/go.mod h1:P6F4/dGMGcx8wh+kG1zrNEd4vnNpEBY/mwEMd/vn6AM=
|
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 h1:MnZVdI987lkjln9BSx/zUb724TZISa2jbO+dPj6BvgQ=
|
||||||
github.com/schollz/pake/v3 v3.0.5/go.mod h1:OGbG6htRwSKo6V8R5tg61ufpFmZM1b/PrrSp6g2ZLLc=
|
github.com/schollz/pake/v3 v3.0.5/go.mod h1:OGbG6htRwSKo6V8R5tg61ufpFmZM1b/PrrSp6g2ZLLc=
|
||||||
github.com/schollz/peerdiscovery v1.7.5 h1:0cEhO+o8i4fpeKBwl7u0UY3Kt3XVt5fSzS4rg17ZPb4=
|
github.com/schollz/peerdiscovery v1.7.3 h1:/pt1G0rZ80fSPoI/FgGC5P7MxpkRXD6u0pe6PJbYcIE=
|
||||||
github.com/schollz/peerdiscovery v1.7.5/go.mod h1:Crht2FOfD1/eL3U/AIM0vvwVZDPePlBgSX3Xw+TnJoE=
|
github.com/schollz/peerdiscovery v1.7.3/go.mod h1:mVlPNJ5DWbMi52VzpXxGbqXKdFANx3qw0Jsp3EQMCrE=
|
||||||
github.com/schollz/progressbar/v3 v3.17.1 h1:bI1MTaoQO+v5kzklBjYNRQLoVpe0zbyRZNK6DFkVC5U=
|
github.com/schollz/progressbar/v3 v3.14.3 h1:oOuWW19ka12wxYU1XblR4n16wF/2Y1dBLMarMo6p4xU=
|
||||||
github.com/schollz/progressbar/v3 v3.17.1/go.mod h1:RzqpnsPQNjUyIgdglUjRLgD7sVnxN1wpmBMV+UiEbL4=
|
github.com/schollz/progressbar/v3 v3.14.3/go.mod h1:aT3UQ7yGm+2ZjeXPqsjTenwL3ddUiuZ0kfQ/2tHlyNI=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
|
||||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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.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 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
|
@ -67,35 +70,22 @@ github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
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/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
|
||||||
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
|
||||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
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.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
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/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
|
||||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
|
||||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|
||||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
@ -103,45 +93,36 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/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.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.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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
|
||||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
|
||||||
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
|
||||||
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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.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.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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
|
|
||||||
32
main.go
32
main.go
|
|
@ -5,13 +5,9 @@ package main
|
||||||
//go:generate git tag -af v$VERSION -m "v$VERSION"
|
//go:generate git tag -af v$VERSION -m "v$VERSION"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"log"
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/schollz/croc/v10/src/cli"
|
"github.com/schollz/croc/v9/src/cli"
|
||||||
"github.com/schollz/croc/v10/src/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
@ -31,25 +27,7 @@ func main() {
|
||||||
// fmt.Println("wrote profile")
|
// fmt.Println("wrote profile")
|
||||||
// }
|
// }
|
||||||
// }()
|
// }()
|
||||||
|
if err := cli.Run(); err != nil {
|
||||||
// Create a channel to receive OS signals
|
log.Fatalln(err)
|
||||||
sigs := make(chan os.Signal, 1)
|
}
|
||||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
if err := cli.Run(); err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
// Exit the program gracefully
|
|
||||||
utils.RemoveMarkedFiles()
|
|
||||||
os.Exit(0)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Wait for a termination signal
|
|
||||||
_ = <-sigs
|
|
||||||
utils.RemoveMarkedFiles()
|
|
||||||
|
|
||||||
// Exit the program gracefully
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
270
src/cli/cli.go
270
src/cli/cli.go
|
|
@ -15,13 +15,13 @@ import (
|
||||||
|
|
||||||
"github.com/chzyer/readline"
|
"github.com/chzyer/readline"
|
||||||
"github.com/schollz/cli/v2"
|
"github.com/schollz/cli/v2"
|
||||||
"github.com/schollz/croc/v10/src/comm"
|
"github.com/schollz/croc/v9/src/comm"
|
||||||
"github.com/schollz/croc/v10/src/croc"
|
"github.com/schollz/croc/v9/src/croc"
|
||||||
"github.com/schollz/croc/v10/src/mnemonicode"
|
"github.com/schollz/croc/v9/src/models"
|
||||||
"github.com/schollz/croc/v10/src/models"
|
"github.com/schollz/croc/v9/src/tcp"
|
||||||
"github.com/schollz/croc/v10/src/tcp"
|
"github.com/schollz/croc/v9/src/utils"
|
||||||
"github.com/schollz/croc/v10/src/utils"
|
|
||||||
log "github.com/schollz/logger"
|
log "github.com/schollz/logger"
|
||||||
|
"github.com/schollz/mnemonicode"
|
||||||
"github.com/schollz/pake/v3"
|
"github.com/schollz/pake/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -36,15 +36,12 @@ func Run() (err error) {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Name = "croc"
|
app.Name = "croc"
|
||||||
if Version == "" {
|
if Version == "" {
|
||||||
Version = "v10.1.0"
|
Version = "v9.6.15"
|
||||||
}
|
}
|
||||||
app.Version = Version
|
app.Version = Version
|
||||||
app.Compiled = time.Now()
|
app.Compiled = time.Now()
|
||||||
app.Usage = "easily and securely transfer stuff from one computer to another"
|
app.Usage = "easily and securely transfer stuff from one computer to another"
|
||||||
app.UsageText = `croc [GLOBAL OPTIONS] [COMMAND] [COMMAND OPTIONS] [filename(s) or folder]
|
app.UsageText = `Send a file:
|
||||||
|
|
||||||
USAGE EXAMPLES:
|
|
||||||
Send a file:
|
|
||||||
croc send file.txt
|
croc send file.txt
|
||||||
|
|
||||||
-git to respect your .gitignore
|
-git to respect your .gitignore
|
||||||
|
|
@ -77,7 +74,6 @@ func Run() (err error) {
|
||||||
&cli.BoolFlag{Name: "git", Usage: "enable .gitignore respect / don't send ignored files"},
|
&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: "port", Value: 9009, Usage: "base port for the relay"},
|
||||||
&cli.IntFlag{Name: "transfers", Value: 4, Usage: "number of ports to use for transfers"},
|
&cli.IntFlag{Name: "transfers", Value: 4, Usage: "number of ports to use for transfers"},
|
||||||
&cli.BoolFlag{Name: "qrcode", Aliases: []string{"qr"}, Usage: "show receive code as a qrcode"},
|
|
||||||
},
|
},
|
||||||
HelpName: "croc send",
|
HelpName: "croc send",
|
||||||
Action: send,
|
Action: send,
|
||||||
|
|
@ -91,14 +87,11 @@ func Run() (err error) {
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{Name: "host", Usage: "host of the relay"},
|
&cli.StringFlag{Name: "host", Usage: "host of the relay"},
|
||||||
&cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the relay"},
|
&cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the relay"},
|
||||||
&cli.IntFlag{Name: "port", Value: 9009, Usage: "base port for the relay"},
|
|
||||||
&cli.IntFlag{Name: "transfers", Value: 5, Usage: "number of ports to use for relay"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
&cli.BoolFlag{Name: "internal-dns", Usage: "use a built-in DNS stub resolver rather than the host operating system"},
|
&cli.BoolFlag{Name: "internal-dns", Usage: "use a built-in DNS stub resolver rather than the host operating system"},
|
||||||
&cli.BoolFlag{Name: "classic", Usage: "toggle between the classic mode (insecure due to local attack vector) and new mode (secure)"},
|
|
||||||
&cli.BoolFlag{Name: "remember", Usage: "save these settings to reuse next time"},
|
&cli.BoolFlag{Name: "remember", Usage: "save these settings to reuse next time"},
|
||||||
&cli.BoolFlag{Name: "debug", Usage: "toggle debug mode"},
|
&cli.BoolFlag{Name: "debug", Usage: "toggle debug mode"},
|
||||||
&cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
|
&cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
|
||||||
|
|
@ -107,9 +100,8 @@ func Run() (err error) {
|
||||||
&cli.BoolFlag{Name: "ask", Usage: "make sure sender and recipient are prompted"},
|
&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: "local", Usage: "force to use only local connections"},
|
||||||
&cli.BoolFlag{Name: "ignore-stdin", Usage: "ignore piped stdin"},
|
&cli.BoolFlag{Name: "ignore-stdin", Usage: "ignore piped stdin"},
|
||||||
&cli.BoolFlag{Name: "overwrite", Usage: "do not prompt to overwrite or resume"},
|
&cli.BoolFlag{Name: "overwrite", Usage: "do not prompt to overwrite"},
|
||||||
&cli.BoolFlag{Name: "testing", Usage: "flag for testing purposes"},
|
&cli.BoolFlag{Name: "testing", Usage: "flag for testing purposes"},
|
||||||
&cli.StringFlag{Name: "multicast", Value: "239.255.255.250", Usage: "multicast address to use for local discovery"},
|
|
||||||
&cli.StringFlag{Name: "curve", Value: "p256", Usage: "choose an encryption curve (" + strings.Join(pake.AvailableCurves(), ", ") + ")"},
|
&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: "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: "relay", Value: models.DEFAULT_RELAY, Usage: "address of the relay", EnvVars: []string{"CROC_RELAY"}},
|
||||||
|
|
@ -133,61 +125,6 @@ func Run() (err error) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if "classic" is set
|
|
||||||
classicFile := getClassicConfigFile(true)
|
|
||||||
classicInsecureMode := utils.Exists(classicFile)
|
|
||||||
if c.Bool("classic") {
|
|
||||||
if classicInsecureMode {
|
|
||||||
// classic mode not enabled
|
|
||||||
fmt.Print(`Classic mode is currently ENABLED.
|
|
||||||
|
|
||||||
Disabling this mode will prevent the shared secret from being visible
|
|
||||||
on the host's process list when passed via the command line. On a
|
|
||||||
multi-user system, this will help ensure that other local users cannot
|
|
||||||
access the shared secret and receive the files instead of the intended
|
|
||||||
recipient.
|
|
||||||
|
|
||||||
Do you wish to continue to DISABLE the classic mode? (y/N) `)
|
|
||||||
choice := strings.ToLower(utils.GetInput(""))
|
|
||||||
if choice == "y" || choice == "yes" {
|
|
||||||
os.Remove(classicFile)
|
|
||||||
fmt.Print("\nClassic mode DISABLED.\n\n")
|
|
||||||
fmt.Print(`To send and receive, export the CROC_SECRET variable with the code phrase:
|
|
||||||
|
|
||||||
Send: CROC_SECRET=*** croc send file.txt
|
|
||||||
|
|
||||||
Receive: CROC_SECRET=*** croc` + "\n\n")
|
|
||||||
} else {
|
|
||||||
fmt.Print("\nClassic mode ENABLED.\n")
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// enable classic mode
|
|
||||||
// touch the file
|
|
||||||
fmt.Print(`Classic mode is currently DISABLED.
|
|
||||||
|
|
||||||
Please note that enabling this mode will make the shared secret visible
|
|
||||||
on the host's process list when passed via the command line. On a
|
|
||||||
multi-user system, this could allow other local users to access the
|
|
||||||
shared secret and receive the files instead of the intended recipient.
|
|
||||||
|
|
||||||
Do you wish to continue to enable the classic mode? (y/N) `)
|
|
||||||
choice := strings.ToLower(utils.GetInput(""))
|
|
||||||
if choice == "y" || choice == "yes" {
|
|
||||||
fmt.Print("\nClassic mode ENABLED.\n\n")
|
|
||||||
os.WriteFile(classicFile, []byte("enabled"), 0o644)
|
|
||||||
fmt.Print(`To send and receive, use the code phrase:
|
|
||||||
|
|
||||||
Send: croc send --code *** file.txt
|
|
||||||
|
|
||||||
Receive: croc ***` + "\n\n")
|
|
||||||
} else {
|
|
||||||
fmt.Print("\nClassic mode DISABLED.\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if trying to send but forgot send, let the user know
|
// if trying to send but forgot send, let the user know
|
||||||
if c.Args().Present() && allStringsAreFiles(c.Args().Slice()) {
|
if c.Args().Present() && allStringsAreFiles(c.Args().Slice()) {
|
||||||
fnames := []string{}
|
fnames := []string{}
|
||||||
|
|
@ -201,7 +138,6 @@ Do you wish to continue to enable the classic mode? (y/N) `)
|
||||||
return send(c)
|
return send(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return receive(c)
|
return receive(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,14 +148,6 @@ func setDebugLevel(c *cli.Context) {
|
||||||
if c.Bool("debug") {
|
if c.Bool("debug") {
|
||||||
log.SetLevel("debug")
|
log.SetLevel("debug")
|
||||||
log.Debug("debug mode on")
|
log.Debug("debug mode on")
|
||||||
// print the public IP address
|
|
||||||
ip, err := utils.PublicIP()
|
|
||||||
if err == nil {
|
|
||||||
log.Debugf("public IP address: %s", ip)
|
|
||||||
} else {
|
|
||||||
log.Debug(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.SetLevel("info")
|
log.SetLevel("info")
|
||||||
}
|
}
|
||||||
|
|
@ -234,15 +162,6 @@ func getSendConfigFile(requireValidPath bool) string {
|
||||||
return path.Join(configFile, "send.json")
|
return path.Join(configFile, "send.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getClassicConfigFile(requireValidPath bool) string {
|
|
||||||
configFile, err := utils.GetConfigDir(requireValidPath)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return path.Join(configFile, "classic_enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getReceiveConfigFile(requireValidPath bool) (string, error) {
|
func getReceiveConfigFile(requireValidPath bool) (string, error) {
|
||||||
configFile, err := utils.GetConfigDir(requireValidPath)
|
configFile, err := utils.GetConfigDir(requireValidPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -281,30 +200,28 @@ func send(c *cli.Context) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
crocOptions := croc.Options{
|
crocOptions := croc.Options{
|
||||||
SharedSecret: c.String("code"),
|
SharedSecret: c.String("code"),
|
||||||
IsSender: true,
|
IsSender: true,
|
||||||
Debug: c.Bool("debug"),
|
Debug: c.Bool("debug"),
|
||||||
NoPrompt: c.Bool("yes"),
|
NoPrompt: c.Bool("yes"),
|
||||||
RelayAddress: c.String("relay"),
|
RelayAddress: c.String("relay"),
|
||||||
RelayAddress6: c.String("relay6"),
|
RelayAddress6: c.String("relay6"),
|
||||||
Stdout: c.Bool("stdout"),
|
Stdout: c.Bool("stdout"),
|
||||||
DisableLocal: c.Bool("no-local"),
|
DisableLocal: c.Bool("no-local"),
|
||||||
OnlyLocal: c.Bool("local"),
|
OnlyLocal: c.Bool("local"),
|
||||||
IgnoreStdin: c.Bool("ignore-stdin"),
|
IgnoreStdin: c.Bool("ignore-stdin"),
|
||||||
RelayPorts: ports,
|
RelayPorts: ports,
|
||||||
Ask: c.Bool("ask"),
|
Ask: c.Bool("ask"),
|
||||||
NoMultiplexing: c.Bool("no-multi"),
|
NoMultiplexing: c.Bool("no-multi"),
|
||||||
RelayPassword: determinePass(c),
|
RelayPassword: determinePass(c),
|
||||||
SendingText: c.String("text") != "",
|
SendingText: c.String("text") != "",
|
||||||
NoCompress: c.Bool("no-compress"),
|
NoCompress: c.Bool("no-compress"),
|
||||||
Overwrite: c.Bool("overwrite"),
|
Overwrite: c.Bool("overwrite"),
|
||||||
Curve: c.String("curve"),
|
Curve: c.String("curve"),
|
||||||
HashAlgorithm: c.String("hash"),
|
HashAlgorithm: c.String("hash"),
|
||||||
ThrottleUpload: c.String("throttleUpload"),
|
ThrottleUpload: c.String("throttleUpload"),
|
||||||
ZipFolder: c.Bool("zip"),
|
ZipFolder: c.Bool("zip"),
|
||||||
GitIgnore: c.Bool("git"),
|
GitIgnore: c.Bool("git"),
|
||||||
ShowQrCode: c.Bool("qrcode"),
|
|
||||||
MulticastAddress: c.String("multicast"),
|
|
||||||
}
|
}
|
||||||
if crocOptions.RelayAddress != models.DEFAULT_RELAY {
|
if crocOptions.RelayAddress != models.DEFAULT_RELAY {
|
||||||
crocOptions.RelayAddress6 = ""
|
crocOptions.RelayAddress6 = ""
|
||||||
|
|
@ -362,7 +279,6 @@ func send(c *cli.Context) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.MarkFileForRemoval(fnames[0])
|
|
||||||
defer func() {
|
defer func() {
|
||||||
e := os.Remove(fnames[0])
|
e := os.Remove(fnames[0])
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
|
@ -374,7 +290,6 @@ func send(c *cli.Context) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
utils.MarkFileForRemoval(fnames[0])
|
|
||||||
defer func() {
|
defer func() {
|
||||||
e := os.Remove(fnames[0])
|
e := os.Remove(fnames[0])
|
||||||
if e != nil {
|
if e != nil {
|
||||||
|
|
@ -389,31 +304,6 @@ func send(c *cli.Context) (err error) {
|
||||||
return errors.New("must specify file: croc send [filename(s) or folder]")
|
return errors.New("must specify file: croc send [filename(s) or folder]")
|
||||||
}
|
}
|
||||||
|
|
||||||
classicInsecureMode := utils.Exists(getClassicConfigFile(true))
|
|
||||||
if !classicInsecureMode {
|
|
||||||
// if operating system is UNIX, then use environmental variable to set the code
|
|
||||||
if (!(runtime.GOOS == "windows") && c.IsSet("code")) || os.Getenv("CROC_SECRET") != "" {
|
|
||||||
crocOptions.SharedSecret = os.Getenv("CROC_SECRET")
|
|
||||||
if crocOptions.SharedSecret == "" {
|
|
||||||
fmt.Printf(`On UNIX systems, to send with a custom code phrase,
|
|
||||||
you need to set the environmental variable CROC_SECRET:
|
|
||||||
|
|
||||||
CROC_SECRET=**** croc send file.txt
|
|
||||||
|
|
||||||
Or you can have the code phrase automatically generated:
|
|
||||||
|
|
||||||
croc send file.txt
|
|
||||||
|
|
||||||
Or you can go back to the classic croc behavior by enabling classic mode:
|
|
||||||
|
|
||||||
croc --classic
|
|
||||||
|
|
||||||
`)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(crocOptions.SharedSecret) == 0 {
|
if len(crocOptions.SharedSecret) == 0 {
|
||||||
// generate code phrase
|
// generate code phrase
|
||||||
crocOptions.SharedSecret = utils.GetRandomName()
|
crocOptions.SharedSecret = utils.GetRandomName()
|
||||||
|
|
@ -431,6 +321,18 @@ Or you can go back to the classic croc behavior by enabling classic mode:
|
||||||
// save the config
|
// save the config
|
||||||
saveConfig(c, crocOptions)
|
saveConfig(c, crocOptions)
|
||||||
|
|
||||||
|
// if operating system is UNIX, then use environmental variable to set the code
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
cr.Options.SharedSecret = os.Getenv("CROC_SECRET")
|
||||||
|
if cr.Options.SharedSecret == "" {
|
||||||
|
fmt.Printf(`To use croc you need to set a code phrase using your environmental variables:
|
||||||
|
|
||||||
|
export CROC_SECRET="yourcodephrasetouse"
|
||||||
|
`)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = cr.Send(minimalFileInfos, emptyFoldersToTransfer, totalNumberFolders)
|
err = cr.Send(minimalFileInfos, emptyFoldersToTransfer, totalNumberFolders)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
@ -529,21 +431,20 @@ func receive(c *cli.Context) (err error) {
|
||||||
comm.Socks5Proxy = c.String("socks5")
|
comm.Socks5Proxy = c.String("socks5")
|
||||||
comm.HttpProxy = c.String("connect")
|
comm.HttpProxy = c.String("connect")
|
||||||
crocOptions := croc.Options{
|
crocOptions := croc.Options{
|
||||||
SharedSecret: c.String("code"),
|
SharedSecret: c.String("code"),
|
||||||
IsSender: false,
|
IsSender: false,
|
||||||
Debug: c.Bool("debug"),
|
Debug: c.Bool("debug"),
|
||||||
NoPrompt: c.Bool("yes"),
|
NoPrompt: c.Bool("yes"),
|
||||||
RelayAddress: c.String("relay"),
|
RelayAddress: c.String("relay"),
|
||||||
RelayAddress6: c.String("relay6"),
|
RelayAddress6: c.String("relay6"),
|
||||||
Stdout: c.Bool("stdout"),
|
Stdout: c.Bool("stdout"),
|
||||||
Ask: c.Bool("ask"),
|
Ask: c.Bool("ask"),
|
||||||
RelayPassword: determinePass(c),
|
RelayPassword: determinePass(c),
|
||||||
OnlyLocal: c.Bool("local"),
|
OnlyLocal: c.Bool("local"),
|
||||||
IP: c.String("ip"),
|
IP: c.String("ip"),
|
||||||
Overwrite: c.Bool("overwrite"),
|
Overwrite: c.Bool("overwrite"),
|
||||||
Curve: c.String("curve"),
|
Curve: c.String("curve"),
|
||||||
TestFlag: c.Bool("testing"),
|
TestFlag: c.Bool("testing"),
|
||||||
MulticastAddress: c.String("multicast"),
|
|
||||||
}
|
}
|
||||||
if crocOptions.RelayAddress != models.DEFAULT_RELAY {
|
if crocOptions.RelayAddress != models.DEFAULT_RELAY {
|
||||||
crocOptions.RelayAddress6 = ""
|
crocOptions.RelayAddress6 = ""
|
||||||
|
|
@ -606,31 +507,6 @@ func receive(c *cli.Context) (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
classicInsecureMode := utils.Exists(getClassicConfigFile(true))
|
|
||||||
if crocOptions.SharedSecret == "" && os.Getenv("CROC_SECRET") != "" {
|
|
||||||
crocOptions.SharedSecret = os.Getenv("CROC_SECRET")
|
|
||||||
} else if !(runtime.GOOS == "windows") && crocOptions.SharedSecret != "" && !classicInsecureMode {
|
|
||||||
crocOptions.SharedSecret = os.Getenv("CROC_SECRET")
|
|
||||||
if crocOptions.SharedSecret == "" {
|
|
||||||
fmt.Printf(`On UNIX systems, to receive with croc you either need
|
|
||||||
to set a code phrase using your environmental variables:
|
|
||||||
|
|
||||||
CROC_SECRET=**** croc
|
|
||||||
|
|
||||||
Or you can specify the code phrase when you run croc without
|
|
||||||
declaring the secret on the command line:
|
|
||||||
|
|
||||||
croc
|
|
||||||
Enter receive code: ****
|
|
||||||
|
|
||||||
Or you can go back to the classic croc behavior by enabling classic mode:
|
|
||||||
|
|
||||||
croc --classic
|
|
||||||
|
|
||||||
`)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if crocOptions.SharedSecret == "" {
|
if crocOptions.SharedSecret == "" {
|
||||||
l, err := readline.NewEx(&readline.Config{
|
l, err := readline.NewEx(&readline.Config{
|
||||||
Prompt: "Enter receive code: ",
|
Prompt: "Enter receive code: ",
|
||||||
|
|
@ -672,6 +548,18 @@ Or you can go back to the classic croc behavior by enabling classic mode:
|
||||||
log.Debugf("wrote %s", configFile)
|
log.Debugf("wrote %s", configFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if operating system is UNIX, then use environmental variable to set the code
|
||||||
|
if runtime.GOOS == "linux" {
|
||||||
|
cr.Options.SharedSecret = os.Getenv("CROC_SECRET")
|
||||||
|
if cr.Options.SharedSecret == "" {
|
||||||
|
fmt.Printf(`To use croc you need to set a code phrase using your environmental variables:
|
||||||
|
|
||||||
|
export CROC_SECRET="yourcodephrasetouse"
|
||||||
|
`)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = cr.Receive()
|
err = cr.Receive()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -683,25 +571,7 @@ func relay(c *cli.Context) (err error) {
|
||||||
debugString = "debug"
|
debugString = "debug"
|
||||||
}
|
}
|
||||||
host := c.String("host")
|
host := c.String("host")
|
||||||
var ports []string
|
ports := strings.Split(c.String("ports"), ",")
|
||||||
|
|
||||||
if c.IsSet("ports") {
|
|
||||||
ports = strings.Split(c.String("ports"), ",")
|
|
||||||
} else {
|
|
||||||
portString := c.Int("port")
|
|
||||||
if portString == 0 {
|
|
||||||
portString = 9009
|
|
||||||
}
|
|
||||||
transfersString := c.Int("transfers")
|
|
||||||
if transfersString == 0 {
|
|
||||||
transfersString = 4
|
|
||||||
}
|
|
||||||
ports = make([]string, transfersString)
|
|
||||||
for i := range ports {
|
|
||||||
ports[i] = strconv.Itoa(portString + i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tcpPorts := strings.Join(ports[1:], ",")
|
tcpPorts := strings.Join(ports[1:], ",")
|
||||||
for i, port := range ports {
|
for i, port := range ports {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/magisterquis/connectproxy"
|
"github.com/magisterquis/connectproxy"
|
||||||
"github.com/schollz/croc/v10/src/utils"
|
"github.com/schollz/croc/v9/src/utils"
|
||||||
log "github.com/schollz/logger"
|
log "github.com/schollz/logger"
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
487
src/croc/croc.go
487
src/croc/croc.go
|
|
@ -3,41 +3,36 @@ package croc
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/time/rate"
|
||||||
|
|
||||||
"github.com/denisbrodbeck/machineid"
|
"github.com/denisbrodbeck/machineid"
|
||||||
ignore "github.com/sabhiram/go-gitignore"
|
ignore "github.com/sabhiram/go-gitignore"
|
||||||
log "github.com/schollz/logger"
|
log "github.com/schollz/logger"
|
||||||
"github.com/schollz/pake/v3"
|
"github.com/schollz/pake/v3"
|
||||||
"github.com/schollz/peerdiscovery"
|
"github.com/schollz/peerdiscovery"
|
||||||
"github.com/schollz/progressbar/v3"
|
"github.com/schollz/progressbar/v3"
|
||||||
"github.com/skip2/go-qrcode"
|
|
||||||
"golang.org/x/term"
|
|
||||||
"golang.org/x/time/rate"
|
|
||||||
|
|
||||||
"github.com/schollz/croc/v10/src/comm"
|
"github.com/schollz/croc/v9/src/comm"
|
||||||
"github.com/schollz/croc/v10/src/compress"
|
"github.com/schollz/croc/v9/src/compress"
|
||||||
"github.com/schollz/croc/v10/src/crypt"
|
"github.com/schollz/croc/v9/src/crypt"
|
||||||
"github.com/schollz/croc/v10/src/message"
|
"github.com/schollz/croc/v9/src/message"
|
||||||
"github.com/schollz/croc/v10/src/models"
|
"github.com/schollz/croc/v9/src/models"
|
||||||
"github.com/schollz/croc/v10/src/tcp"
|
"github.com/schollz/croc/v9/src/tcp"
|
||||||
"github.com/schollz/croc/v10/src/utils"
|
"github.com/schollz/croc/v9/src/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -60,38 +55,30 @@ func Debug(debug bool) {
|
||||||
|
|
||||||
// Options specifies user specific options
|
// Options specifies user specific options
|
||||||
type Options struct {
|
type Options struct {
|
||||||
IsSender bool
|
IsSender bool
|
||||||
SharedSecret string
|
SharedSecret string
|
||||||
RoomName string
|
Debug bool
|
||||||
Debug bool
|
RelayAddress string
|
||||||
RelayAddress string
|
RelayAddress6 string
|
||||||
RelayAddress6 string
|
RelayPorts []string
|
||||||
RelayPorts []string
|
RelayPassword string
|
||||||
RelayPassword string
|
Stdout bool
|
||||||
Stdout bool
|
NoPrompt bool
|
||||||
NoPrompt bool
|
NoMultiplexing bool
|
||||||
NoMultiplexing bool
|
DisableLocal bool
|
||||||
DisableLocal bool
|
OnlyLocal bool
|
||||||
OnlyLocal bool
|
IgnoreStdin bool
|
||||||
IgnoreStdin bool
|
Ask bool
|
||||||
Ask bool
|
SendingText bool
|
||||||
SendingText bool
|
NoCompress bool
|
||||||
NoCompress bool
|
IP string
|
||||||
IP string
|
Overwrite bool
|
||||||
Overwrite bool
|
Curve string
|
||||||
Curve string
|
HashAlgorithm string
|
||||||
HashAlgorithm string
|
ThrottleUpload string
|
||||||
ThrottleUpload string
|
ZipFolder bool
|
||||||
ZipFolder bool
|
TestFlag bool
|
||||||
TestFlag bool
|
GitIgnore bool
|
||||||
GitIgnore bool
|
|
||||||
MulticastAddress string
|
|
||||||
ShowQrCode bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type SimpleMessage struct {
|
|
||||||
Bytes []byte
|
|
||||||
Kind string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client holds the state of the croc transfer
|
// Client holds the state of the croc transfer
|
||||||
|
|
@ -195,15 +182,12 @@ func New(ops Options) (c *Client, err error) {
|
||||||
// setup basic info
|
// setup basic info
|
||||||
c.Options = ops
|
c.Options = ops
|
||||||
Debug(c.Options.Debug)
|
Debug(c.Options.Debug)
|
||||||
|
log.Debugf("options: %+v", c.Options)
|
||||||
|
|
||||||
if len(c.Options.SharedSecret) < 6 {
|
if len(c.Options.SharedSecret) < 6 {
|
||||||
err = fmt.Errorf("code is too short")
|
err = fmt.Errorf("code is too short")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Create a hash of part of the shared secret to use as the room name
|
|
||||||
hashExtra := "croc"
|
|
||||||
roomNameBytes := sha256.Sum256([]byte(c.Options.SharedSecret[:4] + hashExtra))
|
|
||||||
c.Options.RoomName = hex.EncodeToString(roomNameBytes[:])
|
|
||||||
|
|
||||||
c.conn = make([]*comm.Comm, 16)
|
c.conn = make([]*comm.Comm, 16)
|
||||||
|
|
||||||
|
|
@ -230,8 +214,8 @@ func New(ops Options) (c *Client, err error) {
|
||||||
panic("Could not parse given Upload Limit")
|
panic("Could not parse given Upload Limit")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Somehow 4* is necessary
|
||||||
rt = rate.Every(time.Second / time.Duration(uploadLimit))
|
rt = rate.Every(time.Second / (4 * time.Duration(uploadLimit)))
|
||||||
if int(uploadLimit) > minBurstSize {
|
if int(uploadLimit) > minBurstSize {
|
||||||
minBurstSize = int(uploadLimit)
|
minBurstSize = int(uploadLimit)
|
||||||
}
|
}
|
||||||
|
|
@ -310,6 +294,7 @@ func isChild(parentPath, childPath string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return !strings.HasPrefix(relPath, "..")
|
return !strings.HasPrefix(relPath, "..")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function retrieves the important file information
|
// This function retrieves the important file information
|
||||||
|
|
@ -332,7 +317,7 @@ func GetFilesInfo(fnames []string, zipfolder bool, ignoreGit bool) (filesInfo []
|
||||||
paths = append(paths, fname)
|
paths = append(paths, fname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ignoredPaths := make(map[string]bool)
|
var ignoredPaths = make(map[string]bool)
|
||||||
if ignoreGit {
|
if ignoreGit {
|
||||||
wd, wdErr := os.Stat(".gitignore")
|
wd, wdErr := os.Stat(".gitignore")
|
||||||
if wdErr == nil {
|
if wdErr == nil {
|
||||||
|
|
@ -391,7 +376,6 @@ func GetFilesInfo(fnames []string, zipfolder bool, ignoreGit bool) (filesInfo []
|
||||||
fpath = filepath.Dir(fpath)
|
fpath = filepath.Dir(fpath)
|
||||||
dest := filepath.Base(fpath) + ".zip"
|
dest := filepath.Base(fpath) + ".zip"
|
||||||
utils.ZipDirectory(dest, fpath)
|
utils.ZipDirectory(dest, fpath)
|
||||||
utils.MarkFileForRemoval(dest)
|
|
||||||
stat, errStat = os.Lstat(dest)
|
stat, errStat = os.Lstat(dest)
|
||||||
if errStat != nil {
|
if errStat != nil {
|
||||||
err = errStat
|
err = errStat
|
||||||
|
|
@ -426,14 +410,8 @@ func GetFilesInfo(fnames []string, zipfolder bool, ignoreGit bool) (filesInfo []
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
absPathWithSeparator := filepath.Dir(absPath)
|
remoteFolder := strings.TrimPrefix(filepath.Dir(pathName),
|
||||||
if !strings.HasSuffix(absPathWithSeparator, string(os.PathSeparator)) {
|
filepath.Dir(absPath)+string(os.PathSeparator))
|
||||||
absPathWithSeparator += string(os.PathSeparator)
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(absPathWithSeparator, string(os.PathSeparator)+string(os.PathSeparator)) {
|
|
||||||
absPathWithSeparator = strings.TrimSuffix(absPathWithSeparator, string(os.PathSeparator))
|
|
||||||
}
|
|
||||||
remoteFolder := strings.TrimPrefix(filepath.Dir(pathName), absPathWithSeparator)
|
|
||||||
if !info.IsDir() {
|
if !info.IsDir() {
|
||||||
fInfo := FileInfo{
|
fInfo := FileInfo{
|
||||||
Name: info.Name(),
|
Name: info.Name(),
|
||||||
|
|
@ -517,7 +495,7 @@ func (c *Client) sendCollectFiles(filesInfo []FileInfo) (err error) {
|
||||||
c.Options.HashAlgorithm = "xxhash"
|
c.Options.HashAlgorithm = "xxhash"
|
||||||
}
|
}
|
||||||
|
|
||||||
c.FilesToTransfer[i].Hash, err = utils.HashFile(fullPath, c.Options.HashAlgorithm, fileInfo.Size > 1e7)
|
c.FilesToTransfer[i].Hash, err = utils.HashFile(fullPath, c.Options.HashAlgorithm)
|
||||||
log.Debugf("hashed %s to %x using %s", fullPath, c.FilesToTransfer[i].Hash, c.Options.HashAlgorithm)
|
log.Debugf("hashed %s to %x using %s", fullPath, c.FilesToTransfer[i].Hash, c.Options.HashAlgorithm)
|
||||||
totalFilesSize += fileInfo.Size
|
totalFilesSize += fileInfo.Size
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -590,8 +568,6 @@ func (c *Client) broadcastOnLocalNetwork(useipv6 bool) {
|
||||||
}
|
}
|
||||||
if useipv6 {
|
if useipv6 {
|
||||||
settings.IPVersion = peerdiscovery.IPv6
|
settings.IPVersion = peerdiscovery.IPv6
|
||||||
} else {
|
|
||||||
settings.MulticastAddress = c.Options.MulticastAddress
|
|
||||||
}
|
}
|
||||||
|
|
||||||
discoveries, err := peerdiscovery.Discover(settings)
|
discoveries, err := peerdiscovery.Discover(settings)
|
||||||
|
|
@ -606,7 +582,7 @@ func (c *Client) transferOverLocalRelay(errchan chan<- error) {
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
log.Debug("establishing connection")
|
log.Debug("establishing connection")
|
||||||
var banner string
|
var banner string
|
||||||
conn, banner, ipaddr, err := tcp.ConnectToTCPServer("127.0.0.1:"+c.Options.RelayPorts[0], c.Options.RelayPassword, c.Options.RoomName)
|
conn, banner, ipaddr, err := tcp.ConnectToTCPServer("127.0.0.1:"+c.Options.RelayPorts[0], c.Options.RelayPassword, c.Options.SharedSecret[:3])
|
||||||
log.Debugf("banner: %s", banner)
|
log.Debugf("banner: %s", banner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("could not connect to 127.0.0.1:%s: %w", c.Options.RelayPorts[0], err)
|
err = fmt.Errorf("could not connect to 127.0.0.1:%s: %w", c.Options.RelayPorts[0], err)
|
||||||
|
|
@ -653,18 +629,7 @@ func (c *Client) Send(filesInfo []FileInfo, emptyFoldersToTransfer []FileInfo, t
|
||||||
if c.Options.RelayPassword != models.DEFAULT_PASSPHRASE {
|
if c.Options.RelayPassword != models.DEFAULT_PASSPHRASE {
|
||||||
flags.WriteString("--pass " + c.Options.RelayPassword + " ")
|
flags.WriteString("--pass " + c.Options.RelayPassword + " ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, `Code is: %[1]s
|
fmt.Fprintf(os.Stderr, "Code is: %[1]s\nOn the other computer run\n\ncroc %[2]s%[1]s\n", c.Options.SharedSecret, flags.String())
|
||||||
|
|
||||||
On the other computer run:
|
|
||||||
(For Windows)
|
|
||||||
croc %[2]s%[1]s
|
|
||||||
(For Linux/OSX)
|
|
||||||
CROC_SECRET=%[1]q croc %[2]s
|
|
||||||
`, c.Options.SharedSecret, flags.String())
|
|
||||||
copyToClipboard(c.Options.SharedSecret)
|
|
||||||
if c.Options.ShowQrCode {
|
|
||||||
showReceiveCommandQrCode(fmt.Sprintf("%[1]s", c.Options.SharedSecret))
|
|
||||||
}
|
|
||||||
if c.Options.Ask {
|
if c.Options.Ask {
|
||||||
machid, _ := machineid.ID()
|
machid, _ := machineid.ID()
|
||||||
fmt.Fprintf(os.Stderr, "\rYour machine ID is '%s'\n", machid)
|
fmt.Fprintf(os.Stderr, "\rYour machine ID is '%s'\n", machid)
|
||||||
|
|
@ -705,7 +670,7 @@ On the other computer run:
|
||||||
log.Debugf("got host '%v' and port '%v'", host, port)
|
log.Debugf("got host '%v' and port '%v'", host, port)
|
||||||
address = net.JoinHostPort(host, port)
|
address = net.JoinHostPort(host, port)
|
||||||
log.Debugf("trying connection to %s", address)
|
log.Debugf("trying connection to %s", address)
|
||||||
conn, banner, ipaddr, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.RoomName, durations[i])
|
conn, banner, ipaddr, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.SharedSecret[:3], durations[i])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.Options.RelayAddress = address
|
c.Options.RelayAddress = address
|
||||||
break
|
break
|
||||||
|
|
@ -723,34 +688,13 @@ On the other computer run:
|
||||||
}
|
}
|
||||||
log.Debugf("banner: %s", banner)
|
log.Debugf("banner: %s", banner)
|
||||||
log.Debugf("connection established: %+v", conn)
|
log.Debugf("connection established: %+v", conn)
|
||||||
var kB []byte
|
|
||||||
B, _ := pake.InitCurve([]byte(c.Options.SharedSecret[5:]), 1, c.Options.Curve)
|
|
||||||
for {
|
for {
|
||||||
var dataMessage SimpleMessage
|
log.Debug("waiting for bytes")
|
||||||
log.Trace("waiting for bytes")
|
|
||||||
data, errConn := conn.Receive()
|
data, errConn := conn.Receive()
|
||||||
if errConn != nil {
|
if errConn != nil {
|
||||||
log.Tracef("[%+v] had error: %s", conn, errConn.Error())
|
log.Debugf("[%+v] had error: %s", conn, errConn.Error())
|
||||||
}
|
|
||||||
json.Unmarshal(data, &dataMessage)
|
|
||||||
log.Tracef("data: %+v '%s'", data, data)
|
|
||||||
log.Tracef("dataMessage: %s", dataMessage)
|
|
||||||
log.Tracef("kB: %x", kB)
|
|
||||||
// if kB not null, then use it to decrypt
|
|
||||||
if kB != nil {
|
|
||||||
var decryptErr error
|
|
||||||
var dataDecrypt []byte
|
|
||||||
dataDecrypt, decryptErr = crypt.Decrypt(data, kB)
|
|
||||||
if decryptErr != nil {
|
|
||||||
log.Tracef("error decrypting: %v: '%s'", decryptErr, data)
|
|
||||||
} else {
|
|
||||||
// copy dataDecrypt to data
|
|
||||||
data = dataDecrypt
|
|
||||||
log.Tracef("decrypted: %s", data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if bytes.Equal(data, ipRequest) {
|
if bytes.Equal(data, ipRequest) {
|
||||||
log.Tracef("got ipRequest")
|
|
||||||
// recipient wants to try to connect to local ips
|
// recipient wants to try to connect to local ips
|
||||||
var ips []string
|
var ips []string
|
||||||
// only get local ips if the local is enabled
|
// only get local ips if the local is enabled
|
||||||
|
|
@ -758,48 +702,22 @@ On the other computer run:
|
||||||
// get list of local ips
|
// get list of local ips
|
||||||
ips, err = utils.GetLocalIPs()
|
ips, err = utils.GetLocalIPs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Tracef("error getting local ips: %v", err)
|
log.Debugf("error getting local ips: %v", err)
|
||||||
}
|
}
|
||||||
// prepend the port that is being listened to
|
// prepend the port that is being listened to
|
||||||
ips = append([]string{c.Options.RelayPorts[0]}, ips...)
|
ips = append([]string{c.Options.RelayPorts[0]}, ips...)
|
||||||
}
|
}
|
||||||
log.Tracef("sending ips: %+v", ips)
|
bips, _ := json.Marshal(ips)
|
||||||
bips, errIps := json.Marshal(ips)
|
|
||||||
if errIps != nil {
|
|
||||||
log.Tracef("error marshalling ips: %v", errIps)
|
|
||||||
}
|
|
||||||
bips, errIps = crypt.Encrypt(bips, kB)
|
|
||||||
if errIps != nil {
|
|
||||||
log.Tracef("error encrypting ips: %v", errIps)
|
|
||||||
}
|
|
||||||
if err = conn.Send(bips); err != nil {
|
if err = conn.Send(bips); err != nil {
|
||||||
log.Errorf("error sending: %v", err)
|
log.Errorf("error sending: %v", err)
|
||||||
}
|
}
|
||||||
} else if dataMessage.Kind == "pake1" {
|
|
||||||
log.Trace("got pake1")
|
|
||||||
var pakeError error
|
|
||||||
pakeError = B.Update(dataMessage.Bytes)
|
|
||||||
if pakeError == nil {
|
|
||||||
kB, pakeError = B.SessionKey()
|
|
||||||
if pakeError == nil {
|
|
||||||
log.Tracef("dataMessage kB: %x", kB)
|
|
||||||
dataMessage.Bytes = B.Bytes()
|
|
||||||
dataMessage.Kind = "pake2"
|
|
||||||
data, _ = json.Marshal(dataMessage)
|
|
||||||
if pakeError = conn.Send(data); err != nil {
|
|
||||||
log.Errorf("dataMessage error sending: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} else if bytes.Equal(data, handshakeRequest) {
|
} else if bytes.Equal(data, handshakeRequest) {
|
||||||
log.Trace("got handshake")
|
|
||||||
break
|
break
|
||||||
} else if bytes.Equal(data, []byte{1}) {
|
} else if bytes.Equal(data, []byte{1}) {
|
||||||
log.Trace("got ping")
|
log.Debug("got ping")
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
log.Tracef("[%+v] got weird bytes: %+v", conn, data)
|
log.Debugf("[%+v] got weird bytes: %+v", conn, data)
|
||||||
// throttle the reading
|
// throttle the reading
|
||||||
errchan <- fmt.Errorf("gracefully refusing using the public relay")
|
errchan <- fmt.Errorf("gracefully refusing using the public relay")
|
||||||
return
|
return
|
||||||
|
|
@ -837,13 +755,6 @@ On the other computer run:
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func showReceiveCommandQrCode(command string) {
|
|
||||||
qrCode, err := qrcode.New(command, qrcode.Medium)
|
|
||||||
if err == nil {
|
|
||||||
fmt.Println(qrCode.ToSmallString(false))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive will receive a file
|
// Receive will receive a file
|
||||||
func (c *Client) Receive() (err error) {
|
func (c *Client) Receive() (err error) {
|
||||||
fmt.Fprintf(os.Stderr, "connecting...")
|
fmt.Fprintf(os.Stderr, "connecting...")
|
||||||
|
|
@ -879,11 +790,10 @@ func (c *Client) Receive() (err error) {
|
||||||
go func() {
|
go func() {
|
||||||
defer wgDiscovery.Done()
|
defer wgDiscovery.Done()
|
||||||
ipv4discoveries, err1 := peerdiscovery.Discover(peerdiscovery.Settings{
|
ipv4discoveries, err1 := peerdiscovery.Discover(peerdiscovery.Settings{
|
||||||
Limit: 1,
|
Limit: 1,
|
||||||
Payload: []byte("ok"),
|
Payload: []byte("ok"),
|
||||||
Delay: 20 * time.Millisecond,
|
Delay: 20 * time.Millisecond,
|
||||||
TimeLimit: 200 * time.Millisecond,
|
TimeLimit: 200 * time.Millisecond,
|
||||||
MulticastAddress: c.Options.MulticastAddress,
|
|
||||||
})
|
})
|
||||||
if err1 == nil && len(ipv4discoveries) > 0 {
|
if err1 == nil && len(ipv4discoveries) > 0 {
|
||||||
dmux.Lock()
|
dmux.Lock()
|
||||||
|
|
@ -957,7 +867,7 @@ func (c *Client) Receive() (err error) {
|
||||||
log.Debugf("got host '%v' and port '%v'", host, port)
|
log.Debugf("got host '%v' and port '%v'", host, port)
|
||||||
address = net.JoinHostPort(host, port)
|
address = net.JoinHostPort(host, port)
|
||||||
log.Debugf("trying connection to %s", address)
|
log.Debugf("trying connection to %s", address)
|
||||||
c.conn[0], banner, c.ExternalIP, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.RoomName, durations[i])
|
c.conn[0], banner, c.ExternalIP, err = tcp.ConnectToTCPServer(address, c.Options.RelayPassword, c.Options.SharedSecret[:3], durations[i])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.Options.RelayAddress = address
|
c.Options.RelayAddress = address
|
||||||
break
|
break
|
||||||
|
|
@ -978,68 +888,20 @@ func (c *Client) Receive() (err error) {
|
||||||
if c.Options.TestFlag || (!usingLocal && !c.Options.DisableLocal && !isIPset) {
|
if c.Options.TestFlag || (!usingLocal && !c.Options.DisableLocal && !isIPset) {
|
||||||
// ask the sender for their local ips and port
|
// ask the sender for their local ips and port
|
||||||
// and try to connect to them
|
// and try to connect to them
|
||||||
|
log.Debug("sending ips?")
|
||||||
var ips []string
|
var data []byte
|
||||||
err = func() (err error) {
|
if err = c.conn[0].Send(ipRequest); err != nil {
|
||||||
var A *pake.Pake
|
log.Errorf("ips send error: %v", err)
|
||||||
var data []byte
|
}
|
||||||
A, err = pake.InitCurve([]byte(c.Options.SharedSecret[5:]), 0, c.Options.Curve)
|
data, err = c.conn[0].Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
dataMessage := SimpleMessage{
|
|
||||||
Bytes: A.Bytes(),
|
|
||||||
Kind: "pake1",
|
|
||||||
}
|
|
||||||
data, _ = json.Marshal(dataMessage)
|
|
||||||
if err = c.conn[0].Send(data); err != nil {
|
|
||||||
log.Errorf("dataMessage send error: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data, err = c.conn[0].Receive()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(data, &dataMessage)
|
|
||||||
if err != nil || dataMessage.Kind != "pake2" {
|
|
||||||
log.Debugf("data: %s", data)
|
|
||||||
return fmt.Errorf("dataMessage %s pake failed", ipRequest)
|
|
||||||
}
|
|
||||||
err = A.Update(dataMessage.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var kA []byte
|
|
||||||
kA, err = A.SessionKey()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Debugf("dataMessage kA: %x", kA)
|
|
||||||
|
|
||||||
// secure ipRequest
|
|
||||||
data, err = crypt.Encrypt([]byte(ipRequest), kA)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Debug("sending ips?")
|
|
||||||
if err = c.conn[0].Send(data); err != nil {
|
|
||||||
log.Errorf("ips send error: %v", err)
|
|
||||||
}
|
|
||||||
data, err = c.conn[0].Receive()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
data, err = crypt.Decrypt(data, kA)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Debugf("ips data: %s", data)
|
|
||||||
if err = json.Unmarshal(data, &ips); err != nil {
|
|
||||||
log.Debugf("ips unmarshal error: %v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}()
|
}
|
||||||
|
log.Debugf("ips data: %s", data)
|
||||||
|
var ips []string
|
||||||
|
if err = json.Unmarshal(data, &ips); err != nil {
|
||||||
|
log.Debugf("ips unmarshal error: %v", err)
|
||||||
|
}
|
||||||
if len(ips) > 1 {
|
if len(ips) > 1 {
|
||||||
port := ips[0]
|
port := ips[0]
|
||||||
ips = ips[1:]
|
ips = ips[1:]
|
||||||
|
|
@ -1063,7 +925,7 @@ func (c *Client) Receive() (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
serverTry := net.JoinHostPort(ip, port)
|
serverTry := net.JoinHostPort(ip, port)
|
||||||
conn, banner2, externalIP, errConn := tcp.ConnectToTCPServer(serverTry, c.Options.RelayPassword, c.Options.RoomName, 500*time.Millisecond)
|
conn, banner2, externalIP, errConn := tcp.ConnectToTCPServer(serverTry, c.Options.RelayPassword, c.Options.SharedSecret[:3], 500*time.Millisecond)
|
||||||
if errConn != nil {
|
if errConn != nil {
|
||||||
log.Debug(errConn)
|
log.Debug(errConn)
|
||||||
log.Debugf("could not connect to " + serverTry)
|
log.Debugf("could not connect to " + serverTry)
|
||||||
|
|
@ -1096,7 +958,7 @@ func (c *Client) Receive() (err error) {
|
||||||
err = c.transfer()
|
err = c.transfer()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if c.numberOfTransferredFiles+len(c.EmptyFoldersToTransfer) == 0 {
|
if c.numberOfTransferredFiles+len(c.EmptyFoldersToTransfer) == 0 {
|
||||||
fmt.Fprintf(os.Stderr, "\rNo files transferred.\n")
|
fmt.Fprintf(os.Stderr, "\rNo files transferred.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
@ -1135,7 +997,6 @@ func (c *Client) transfer() (err error) {
|
||||||
}
|
}
|
||||||
done, err = c.processMessage(data)
|
done, err = c.processMessage(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("data: %s", data)
|
|
||||||
log.Debugf("got error processing: %v", err)
|
log.Debugf("got error processing: %v", err)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -1231,31 +1092,6 @@ func (c *Client) processMessageFileInfo(m message.Message) (done bool, err error
|
||||||
c.EmptyFoldersToTransfer = senderInfo.EmptyFoldersToTransfer
|
c.EmptyFoldersToTransfer = senderInfo.EmptyFoldersToTransfer
|
||||||
c.TotalNumberFolders = senderInfo.TotalNumberFolders
|
c.TotalNumberFolders = senderInfo.TotalNumberFolders
|
||||||
c.FilesToTransfer = senderInfo.FilesToTransfer
|
c.FilesToTransfer = senderInfo.FilesToTransfer
|
||||||
for i, fi := range c.FilesToTransfer {
|
|
||||||
// Issues #593 - sanitize the sender paths and prevent ".." from being used
|
|
||||||
c.FilesToTransfer[i].FolderRemote = filepath.Clean(fi.FolderRemote)
|
|
||||||
if strings.Contains(c.FilesToTransfer[i].FolderRemote, "../") {
|
|
||||||
return true, fmt.Errorf("invalid path detected: '%s'", fi.FolderRemote)
|
|
||||||
}
|
|
||||||
if strings.Contains(c.FilesToTransfer[i].FolderRemote, "/..") {
|
|
||||||
return true, fmt.Errorf("invalid path detected: '%s'", fi.FolderRemote)
|
|
||||||
}
|
|
||||||
if strings.Contains(c.FilesToTransfer[i].FolderRemote, "\\..") {
|
|
||||||
return true, fmt.Errorf("invalid path detected: '%s'", fi.FolderRemote)
|
|
||||||
}
|
|
||||||
if strings.Contains(c.FilesToTransfer[i].FolderRemote, "..\\") {
|
|
||||||
return true, fmt.Errorf("invalid path detected: '%s'", fi.FolderRemote)
|
|
||||||
}
|
|
||||||
// Issues #593 - disallow specific folders like .ssh
|
|
||||||
if strings.Contains(c.FilesToTransfer[i].FolderRemote, ".ssh") {
|
|
||||||
return true, fmt.Errorf("invalid path detected: '%s'", fi.FolderRemote)
|
|
||||||
}
|
|
||||||
// Issue #595 - disallow filenames with invisible characters
|
|
||||||
errFileName := utils.ValidFileName(path.Join(c.FilesToTransfer[i].FolderRemote, fi.Name))
|
|
||||||
if errFileName != nil {
|
|
||||||
return true, errFileName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.TotalNumberOfContents = 0
|
c.TotalNumberOfContents = 0
|
||||||
if c.FilesToTransfer != nil {
|
if c.FilesToTransfer != nil {
|
||||||
c.TotalNumberOfContents += len(c.FilesToTransfer)
|
c.TotalNumberOfContents += len(c.FilesToTransfer)
|
||||||
|
|
@ -1293,12 +1129,6 @@ func (c *Client) processMessageFileInfo(m message.Message) (done bool, err error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// // check the totalSize does not exceed disk space
|
|
||||||
// usage := diskusage.NewDiskUsage(".")
|
|
||||||
// if usage.Available() < uint64(totalSize) {
|
|
||||||
// return true, fmt.Errorf("not enough disk space")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// c.spinner.Stop()
|
// c.spinner.Stop()
|
||||||
action := "Accept"
|
action := "Accept"
|
||||||
if c.Options.SendingText {
|
if c.Options.SendingText {
|
||||||
|
|
@ -1445,7 +1275,7 @@ func (c *Client) processMessagePake(m message.Message) (err error) {
|
||||||
c.conn[j+1], _, _, err = tcp.ConnectToTCPServer(
|
c.conn[j+1], _, _, err = tcp.ConnectToTCPServer(
|
||||||
server,
|
server,
|
||||||
c.Options.RelayPassword,
|
c.Options.RelayPassword,
|
||||||
fmt.Sprintf("%s-%d", c.Options.RoomName, j),
|
fmt.Sprintf("%s-%d", utils.SHA256(c.Options.SharedSecret[:5])[:6], j),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
@ -1686,7 +1516,6 @@ func (c *Client) recipientGetFileReady(finished bool) (err error) {
|
||||||
}
|
}
|
||||||
c.SuccessfulTransfer = true
|
c.SuccessfulTransfer = true
|
||||||
c.FilesHasFinished[c.FilesToTransferCurrentNum] = struct{}{}
|
c.FilesHasFinished[c.FilesToTransferCurrentNum] = struct{}{}
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = c.recipientInitializeFile()
|
err = c.recipientInitializeFile()
|
||||||
|
|
@ -1722,25 +1551,6 @@ func (c *Client) recipientGetFileReady(finished bool) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func max(a int, b int) int {
|
|
||||||
if a > b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatDescription(description string) string {
|
|
||||||
width, _, err := term.GetSize(int(os.Stdout.Fd()))
|
|
||||||
width = max(20, width-60)
|
|
||||||
if err != nil {
|
|
||||||
return description
|
|
||||||
}
|
|
||||||
if len(description) > width {
|
|
||||||
description = description[:(width-3)] + "..."
|
|
||||||
}
|
|
||||||
return description
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) createEmptyFileAndFinish(fileInfo FileInfo, i int) (err error) {
|
func (c *Client) createEmptyFileAndFinish(fileInfo FileInfo, i int) (err error) {
|
||||||
log.Debugf("touching file with folder / name")
|
log.Debugf("touching file with folder / name")
|
||||||
if !utils.Exists(fileInfo.FolderRemote) {
|
if !utils.Exists(fileInfo.FolderRemote) {
|
||||||
|
|
@ -1783,7 +1593,7 @@ func (c *Client) createEmptyFileAndFinish(fileInfo FileInfo, i int) (err error)
|
||||||
c.fmtPrintUpdate()
|
c.fmtPrintUpdate()
|
||||||
}),
|
}),
|
||||||
progressbar.OptionSetWidth(20),
|
progressbar.OptionSetWidth(20),
|
||||||
progressbar.OptionSetDescription(formatDescription(description)),
|
progressbar.OptionSetDescription(description),
|
||||||
progressbar.OptionSetRenderBlankState(true),
|
progressbar.OptionSetRenderBlankState(true),
|
||||||
progressbar.OptionShowBytes(true),
|
progressbar.OptionShowBytes(true),
|
||||||
progressbar.OptionShowCount(),
|
progressbar.OptionShowCount(),
|
||||||
|
|
@ -1839,13 +1649,13 @@ func (c *Client) updateIfRecipientHasFileInfo() (err error) {
|
||||||
percentDone := 100 - float64(len(missingChunks)*models.TCP_BUFFER_SIZE/2)/float64(fileInfo.Size)*100
|
percentDone := 100 - float64(len(missingChunks)*models.TCP_BUFFER_SIZE/2)/float64(fileInfo.Size)*100
|
||||||
|
|
||||||
log.Debug("asking to overwrite")
|
log.Debug("asking to overwrite")
|
||||||
prompt := fmt.Sprintf("\nOverwrite '%s'? (y/N) (use --overwrite to omit) ", path.Join(fileInfo.FolderRemote, fileInfo.Name))
|
prompt := fmt.Sprintf("\nOverwrite '%s'? (y/N) ", path.Join(fileInfo.FolderRemote, fileInfo.Name))
|
||||||
if percentDone < 99 {
|
if percentDone < 99 {
|
||||||
prompt = fmt.Sprintf("\nResume '%s' (%2.1f%%)? (y/N) (use --overwrite to omit) ", path.Join(fileInfo.FolderRemote, fileInfo.Name), percentDone)
|
prompt = fmt.Sprintf("\nResume '%s' (%2.1f%%)? (y/N) ", path.Join(fileInfo.FolderRemote, fileInfo.Name), percentDone)
|
||||||
}
|
}
|
||||||
choice := strings.ToLower(utils.GetInput(prompt))
|
choice := strings.ToLower(utils.GetInput(prompt))
|
||||||
if choice != "y" && choice != "yes" {
|
if choice != "y" && choice != "yes" {
|
||||||
fmt.Fprintf(os.Stderr, "Skipping '%s'\n", path.Join(fileInfo.FolderRemote, fileInfo.Name))
|
fmt.Fprintf(os.Stderr, "skipping '%s'", path.Join(fileInfo.FolderRemote, fileInfo.Name))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1907,13 +1717,12 @@ func (c *Client) updateState() (err error) {
|
||||||
description = c.FilesToTransfer[i].Name
|
description = c.FilesToTransfer[i].Name
|
||||||
// description = ""
|
// description = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
c.bar = progressbar.NewOptions64(1,
|
c.bar = progressbar.NewOptions64(1,
|
||||||
progressbar.OptionOnCompletion(func() {
|
progressbar.OptionOnCompletion(func() {
|
||||||
c.fmtPrintUpdate()
|
c.fmtPrintUpdate()
|
||||||
}),
|
}),
|
||||||
progressbar.OptionSetWidth(20),
|
progressbar.OptionSetWidth(20),
|
||||||
progressbar.OptionSetDescription(formatDescription(description)),
|
progressbar.OptionSetDescription(description),
|
||||||
progressbar.OptionSetRenderBlankState(true),
|
progressbar.OptionSetRenderBlankState(true),
|
||||||
progressbar.OptionShowBytes(true),
|
progressbar.OptionShowBytes(true),
|
||||||
progressbar.OptionShowCount(),
|
progressbar.OptionShowCount(),
|
||||||
|
|
@ -1961,7 +1770,7 @@ func (c *Client) setBar() {
|
||||||
c.fmtPrintUpdate()
|
c.fmtPrintUpdate()
|
||||||
}),
|
}),
|
||||||
progressbar.OptionSetWidth(20),
|
progressbar.OptionSetWidth(20),
|
||||||
progressbar.OptionSetDescription(formatDescription(description)),
|
progressbar.OptionSetDescription(description),
|
||||||
progressbar.OptionSetRenderBlankState(true),
|
progressbar.OptionSetRenderBlankState(true),
|
||||||
progressbar.OptionShowBytes(true),
|
progressbar.OptionShowBytes(true),
|
||||||
progressbar.OptionShowCount(),
|
progressbar.OptionShowCount(),
|
||||||
|
|
@ -1982,14 +1791,14 @@ func (c *Client) setBar() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) receiveData(i int) {
|
func (c *Client) receiveData(i int) {
|
||||||
log.Tracef("%d receiving data", i)
|
log.Debugf("%d receiving data", i)
|
||||||
for {
|
for {
|
||||||
data, err := c.conn[i+1].Receive()
|
data, err := c.conn[i+1].Receive()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if bytes.Equal(data, []byte{1}) {
|
if bytes.Equal(data, []byte{1}) {
|
||||||
log.Trace("got ping")
|
log.Debug("got ping")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2065,66 +1874,62 @@ func (c *Client) sendData(i int) {
|
||||||
curi := float64(0)
|
curi := float64(0)
|
||||||
for {
|
for {
|
||||||
// Read file
|
// Read file
|
||||||
var n int
|
data := make([]byte, models.TCP_BUFFER_SIZE/2)
|
||||||
var errRead error
|
// log.Debugf("%d trying to read", i)
|
||||||
if math.Mod(curi, float64(len(c.Options.RelayPorts))) == float64(i) {
|
n, errRead := c.fread.ReadAt(data, readingPos)
|
||||||
data := make([]byte, models.TCP_BUFFER_SIZE/2)
|
// log.Debugf("%d read %d bytes", i, n)
|
||||||
n, errRead = c.fread.ReadAt(data, readingPos)
|
|
||||||
if c.limiter != nil {
|
|
||||||
r := c.limiter.ReserveN(time.Now(), n)
|
|
||||||
log.Debugf("Limiting Upload for %d", r.Delay())
|
|
||||||
time.Sleep(r.Delay())
|
|
||||||
}
|
|
||||||
if n > 0 {
|
|
||||||
// check to see if this is a chunk that the recipient wants
|
|
||||||
usableChunk := true
|
|
||||||
c.mutex.Lock()
|
|
||||||
if len(c.chunkMap) != 0 {
|
|
||||||
if _, ok := c.chunkMap[pos]; !ok {
|
|
||||||
usableChunk = false
|
|
||||||
} else {
|
|
||||||
delete(c.chunkMap, pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.mutex.Unlock()
|
|
||||||
if usableChunk {
|
|
||||||
// log.Debugf("sending chunk %d", pos)
|
|
||||||
posByte := make([]byte, 8)
|
|
||||||
binary.LittleEndian.PutUint64(posByte, pos)
|
|
||||||
var err error
|
|
||||||
var dataToSend []byte
|
|
||||||
if c.Options.NoCompress {
|
|
||||||
dataToSend, err = crypt.Encrypt(
|
|
||||||
append(posByte, data[:n]...),
|
|
||||||
c.Key,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
dataToSend, err = crypt.Encrypt(
|
|
||||||
compress.Compress(
|
|
||||||
append(posByte, data[:n]...),
|
|
||||||
),
|
|
||||||
c.Key,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.conn[i+1].Send(dataToSend)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
c.bar.Add(n)
|
|
||||||
c.TotalSent += int64(n)
|
|
||||||
// time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == 0 {
|
|
||||||
n = models.TCP_BUFFER_SIZE / 2
|
|
||||||
}
|
|
||||||
readingPos += int64(n)
|
readingPos += int64(n)
|
||||||
|
if c.limiter != nil {
|
||||||
|
r := c.limiter.ReserveN(time.Now(), n)
|
||||||
|
log.Debugf("Limiting Upload for %d", r.Delay())
|
||||||
|
time.Sleep(r.Delay())
|
||||||
|
}
|
||||||
|
|
||||||
|
if math.Mod(curi, float64(len(c.Options.RelayPorts))) == float64(i) {
|
||||||
|
// check to see if this is a chunk that the recipient wants
|
||||||
|
usableChunk := true
|
||||||
|
c.mutex.Lock()
|
||||||
|
if len(c.chunkMap) != 0 {
|
||||||
|
if _, ok := c.chunkMap[pos]; !ok {
|
||||||
|
usableChunk = false
|
||||||
|
} else {
|
||||||
|
delete(c.chunkMap, pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.mutex.Unlock()
|
||||||
|
if usableChunk {
|
||||||
|
// log.Debugf("sending chunk %d", pos)
|
||||||
|
posByte := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(posByte, pos)
|
||||||
|
var err error
|
||||||
|
var dataToSend []byte
|
||||||
|
if c.Options.NoCompress {
|
||||||
|
dataToSend, err = crypt.Encrypt(
|
||||||
|
append(posByte, data[:n]...),
|
||||||
|
c.Key,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
dataToSend, err = crypt.Encrypt(
|
||||||
|
compress.Compress(
|
||||||
|
append(posByte, data[:n]...),
|
||||||
|
),
|
||||||
|
c.Key,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.conn[i+1].Send(dataToSend)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c.bar.Add(n)
|
||||||
|
c.TotalSent += int64(n)
|
||||||
|
// time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
curi++
|
curi++
|
||||||
pos += uint64(n)
|
pos += uint64(n)
|
||||||
|
|
||||||
|
|
@ -2136,27 +1941,3 @@ func (c *Client) sendData(i int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyToClipboard(str string) {
|
|
||||||
var cmd *exec.Cmd
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "windows":
|
|
||||||
cmd = exec.Command("clip")
|
|
||||||
case "darwin":
|
|
||||||
cmd = exec.Command("pbcopy")
|
|
||||||
case "linux":
|
|
||||||
if os.Getenv("XDG_SESSION_TYPE") == "wayland" {
|
|
||||||
cmd = exec.Command("wl-copy")
|
|
||||||
} else {
|
|
||||||
cmd = exec.Command("xclip", "-selection", "clipboard")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cmd.Stdin = bytes.NewReader([]byte(str))
|
|
||||||
if err := cmd.Run(); err != nil {
|
|
||||||
log.Debugf("error copying to clipboard: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Fprintf(os.Stderr, "Code copied to clipboard\n")
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/schollz/croc/v10/src/tcp"
|
"github.com/schollz/croc/v9/src/tcp"
|
||||||
log "github.com/schollz/logger"
|
log "github.com/schollz/logger"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
@ -232,7 +232,7 @@ func TestCrocSymlink(t *testing.T) {
|
||||||
t.Errorf("symlink transfer failed: %s", err.Error())
|
t.Errorf("symlink transfer failed: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestCrocIgnoreGit(t *testing.T) {
|
func testCrocIgnoreGit(t *testing.T) {
|
||||||
log.SetLevel("trace")
|
log.SetLevel("trace")
|
||||||
defer os.Remove(".gitignore")
|
defer os.Remove(".gitignore")
|
||||||
time.Sleep(300 * time.Millisecond)
|
time.Sleep(300 * time.Millisecond)
|
||||||
|
|
|
||||||
|
|
@ -24,20 +24,6 @@ func BenchmarkDecrypt(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkNewPbkdf2(b *testing.B) {
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
New([]byte("password"), nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkNewArgon2(b *testing.B) {
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
NewArgon2([]byte("password"), nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkEncryptChaCha(b *testing.B) {
|
func BenchmarkEncryptChaCha(b *testing.B) {
|
||||||
bob, _, _ := NewArgon2([]byte("password"), nil)
|
bob, _, _ := NewArgon2([]byte("password"), nil)
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
|
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
//go:build !windows
|
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package diskusage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DiskUsage contains usage data and provides user-friendly access methods
|
|
||||||
type DiskUsage struct {
|
|
||||||
stat *unix.Statfs_t
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDiskUsage returns an object holding the disk usage of volumePath
|
|
||||||
// or nil in case of error (invalid path, etc)
|
|
||||||
func NewDiskUsage(volumePath string) *DiskUsage {
|
|
||||||
stat := unix.Statfs_t{}
|
|
||||||
err := unix.Statfs(volumePath, &stat)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &DiskUsage{&stat}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free returns total free bytes on file system
|
|
||||||
func (du *DiskUsage) Free() uint64 {
|
|
||||||
return uint64(du.stat.Bfree) * uint64(du.stat.Bsize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Available return total available bytes on file system to an unprivileged user
|
|
||||||
func (du *DiskUsage) Available() uint64 {
|
|
||||||
return uint64(du.stat.Bavail) * uint64(du.stat.Bsize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns total size of the file system
|
|
||||||
func (du *DiskUsage) Size() uint64 {
|
|
||||||
return uint64(du.stat.Blocks) * uint64(du.stat.Bsize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used returns total bytes used in file system
|
|
||||||
func (du *DiskUsage) Used() uint64 {
|
|
||||||
return du.Size() - du.Free()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usage returns percentage of use on the file system
|
|
||||||
func (du *DiskUsage) Usage() float32 {
|
|
||||||
return float32(du.Used()) / float32(du.Size())
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package diskusage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var KB = uint64(1024)
|
|
||||||
|
|
||||||
func TestNewDiskUsage(t *testing.T) {
|
|
||||||
usage := NewDiskUsage(".")
|
|
||||||
fmt.Println("Free:", usage.Free()/(KB*KB))
|
|
||||||
fmt.Println("Available:", usage.Available()/(KB*KB))
|
|
||||||
fmt.Println("Size:", usage.Size()/(KB*KB))
|
|
||||||
fmt.Println("Used:", usage.Used()/(KB*KB))
|
|
||||||
fmt.Println("Usage:", usage.Usage()*100, "%")
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
package diskusage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DiskUsage struct {
|
|
||||||
freeBytes int64
|
|
||||||
totalBytes int64
|
|
||||||
availBytes int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDiskUsage returns an object holding the disk usage of volumePath
|
|
||||||
// or nil in case of error (invalid path, etc)
|
|
||||||
func NewDiskUsage(volumePath string) *DiskUsage {
|
|
||||||
h := windows.MustLoadDLL("kernel32.dll")
|
|
||||||
c := h.MustFindProc("GetDiskFreeSpaceExW")
|
|
||||||
|
|
||||||
du := &DiskUsage{}
|
|
||||||
|
|
||||||
c.Call(
|
|
||||||
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(volumePath))),
|
|
||||||
uintptr(unsafe.Pointer(&du.freeBytes)),
|
|
||||||
uintptr(unsafe.Pointer(&du.totalBytes)),
|
|
||||||
uintptr(unsafe.Pointer(&du.availBytes)))
|
|
||||||
|
|
||||||
return du
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free returns total free bytes on file system
|
|
||||||
func (du *DiskUsage) Free() uint64 {
|
|
||||||
return uint64(du.freeBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Available returns total available bytes on file system to an unprivileged user
|
|
||||||
func (du *DiskUsage) Available() uint64 {
|
|
||||||
return uint64(du.availBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns total size of the file system
|
|
||||||
func (du *DiskUsage) Size() uint64 {
|
|
||||||
return uint64(du.totalBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used returns total bytes used in file system
|
|
||||||
func (du *DiskUsage) Used() uint64 {
|
|
||||||
return du.Size() - du.Free()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usage returns percentage of use on the file system
|
|
||||||
func (du *DiskUsage) Usage() float32 {
|
|
||||||
return float32(du.Used()) / float32(du.Size())
|
|
||||||
}
|
|
||||||
|
|
@ -528,7 +528,7 @@ main() {
|
||||||
local autocomplete_install_rcode
|
local autocomplete_install_rcode
|
||||||
|
|
||||||
croc_bin_name="croc"
|
croc_bin_name="croc"
|
||||||
croc_version="10.1.1"
|
croc_version="9.6.15"
|
||||||
croc_dl_ext="tar.gz"
|
croc_dl_ext="tar.gz"
|
||||||
croc_base_url="https://github.com/schollz/croc/releases/download"
|
croc_base_url="https://github.com/schollz/croc/releases/download"
|
||||||
prefix="${1}"
|
prefix="${1}"
|
||||||
|
|
@ -577,9 +577,6 @@ main() {
|
||||||
|
|
||||||
case "${croc_os}" in
|
case "${croc_os}" in
|
||||||
"Darwin" ) croc_os="macOS";;
|
"Darwin" ) croc_os="macOS";;
|
||||||
*"BusyBox"* )
|
|
||||||
croc_os="Linux"
|
|
||||||
;;
|
|
||||||
"CYGWIN"* ) croc_os="Windows";
|
"CYGWIN"* ) croc_os="Windows";
|
||||||
croc_dl_ext="zip";
|
croc_dl_ext="zip";
|
||||||
print_message "== Cygwin is currently unsupported." "error";
|
print_message "== Cygwin is currently unsupported." "error";
|
||||||
|
|
@ -592,8 +589,6 @@ main() {
|
||||||
"aarch64" ) croc_arch="ARM64";;
|
"aarch64" ) croc_arch="ARM64";;
|
||||||
"arm64" ) croc_arch="ARM64";;
|
"arm64" ) croc_arch="ARM64";;
|
||||||
"armv7l" ) croc_arch="ARM";;
|
"armv7l" ) croc_arch="ARM";;
|
||||||
"armv8l" ) croc_arch="ARM";;
|
|
||||||
"armv9l" ) croc_arch="ARM";;
|
|
||||||
"i686" ) croc_arch="32bit";;
|
"i686" ) croc_arch="32bit";;
|
||||||
* ) croc_arch="unknown";;
|
* ) croc_arch="unknown";;
|
||||||
esac
|
esac
|
||||||
|
|
@ -690,7 +685,7 @@ main() {
|
||||||
print_message "== Install prefix already exists. No need to create it." "info"
|
print_message "== Install prefix already exists. No need to create it." "info"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ ! -d "${bash_autocomplete_prefix}/croc" ] && mkdir -p "${bash_autocomplete_prefix}/croc" >/dev/null 2>&1
|
[ ! -d "/etc/bash_completion.d/croc" ] && mkdir -p "/etc/bash_completion.d/croc"
|
||||||
case "${croc_os}" in
|
case "${croc_os}" in
|
||||||
"Linux" ) install_file_linux "${tmpdir}/${croc_bin_name}" "${prefix}/";
|
"Linux" ) install_file_linux "${tmpdir}/${croc_bin_name}" "${prefix}/";
|
||||||
install_file_rcode="${?}";;
|
install_file_rcode="${?}";;
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ package message
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/schollz/croc/v10/src/comm"
|
"github.com/schollz/croc/v9/src/comm"
|
||||||
"github.com/schollz/croc/v10/src/compress"
|
"github.com/schollz/croc/v9/src/compress"
|
||||||
"github.com/schollz/croc/v10/src/crypt"
|
"github.com/schollz/croc/v9/src/crypt"
|
||||||
log "github.com/schollz/logger"
|
log "github.com/schollz/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/schollz/croc/v10/src/comm"
|
"github.com/schollz/croc/v9/src/comm"
|
||||||
"github.com/schollz/croc/v10/src/crypt"
|
"github.com/schollz/croc/v9/src/crypt"
|
||||||
log "github.com/schollz/logger"
|
log "github.com/schollz/logger"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
@ -84,7 +84,7 @@ func TestSend(t *testing.T) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
time.Sleep(800 * time.Millisecond)
|
time.Sleep(300 * time.Millisecond)
|
||||||
a, err := comm.NewConnection("127.0.0.1:"+port, 10*time.Minute)
|
a, err := comm.NewConnection("127.0.0.1:"+port, 10*time.Minute)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
m := Message{Type: TypeMessage, Message: "hello, world"}
|
m := Message{Type: TypeMessage, Message: "hello, world"}
|
||||||
|
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
// From GitHub version/fork maintained by Stephen Paul Weber available at:
|
|
||||||
// https://github.com/singpolyma/mnemonicode
|
|
||||||
//
|
|
||||||
// Originally from:
|
|
||||||
// http://web.archive.org/web/20101031205747/http://www.tothink.com/mnemonic/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (c) 2000 Oren Tirosh <oren@hishome.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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package mnemonicode
|
|
||||||
|
|
||||||
const base = 1626
|
|
||||||
|
|
||||||
// WordsRequired returns the number of words required to encode input
|
|
||||||
// data of length bytes using mnomonic encoding.
|
|
||||||
//
|
|
||||||
// Every four bytes of input is encoded into three words. If there
|
|
||||||
// is an extra one or two bytes they get an extra one or two words
|
|
||||||
// respectively. If there is an extra three bytes, they will be encoded
|
|
||||||
// into three words with the last word being one of a small set of very
|
|
||||||
// short words (only needed to encode the last 3 bits).
|
|
||||||
func WordsRequired(length int) int {
|
|
||||||
return ((length + 1) * 3) / 4
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeWordList encodes src into mnemomic words which are appended to dst.
|
|
||||||
// The final wordlist is returned.
|
|
||||||
// There will be WordsRequired(len(src)) words appeneded.
|
|
||||||
func EncodeWordList(dst []string, src []byte) (result []string) {
|
|
||||||
if n := len(dst) + WordsRequired(len(src)); cap(dst) < n {
|
|
||||||
result = make([]string, len(dst), n)
|
|
||||||
copy(result, dst)
|
|
||||||
} else {
|
|
||||||
result = dst
|
|
||||||
}
|
|
||||||
|
|
||||||
var x uint32
|
|
||||||
for len(src) >= 4 {
|
|
||||||
x = uint32(src[0])
|
|
||||||
x |= uint32(src[1]) << 8
|
|
||||||
x |= uint32(src[2]) << 16
|
|
||||||
x |= uint32(src[3]) << 24
|
|
||||||
src = src[4:]
|
|
||||||
|
|
||||||
i0 := int(x % base)
|
|
||||||
i1 := int(x/base) % base
|
|
||||||
i2 := int(x/base/base) % base
|
|
||||||
result = append(result, WordList[i0], WordList[i1], WordList[i2])
|
|
||||||
}
|
|
||||||
if len(src) > 0 {
|
|
||||||
x = 0
|
|
||||||
for i := len(src) - 1; i >= 0; i-- {
|
|
||||||
x <<= 8
|
|
||||||
x |= uint32(src[i])
|
|
||||||
}
|
|
||||||
i := int(x % base)
|
|
||||||
result = append(result, WordList[i])
|
|
||||||
if len(src) >= 2 {
|
|
||||||
i = int(x/base) % base
|
|
||||||
result = append(result, WordList[i])
|
|
||||||
}
|
|
||||||
if len(src) == 3 {
|
|
||||||
i = base + int(x/base/base)%7
|
|
||||||
result = append(result, WordList[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
@ -1,318 +0,0 @@
|
||||||
// From GitHub version/fork maintained by Stephen Paul Weber available at:
|
|
||||||
// https://github.com/singpolyma/mnemonicode
|
|
||||||
//
|
|
||||||
// Originally from:
|
|
||||||
// http://web.archive.org/web/20101031205747/http://www.tothink.com/mnemonic/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Copyright (c) 2000 Oren Tirosh <oren@hishome.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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package mnemonicode
|
|
||||||
|
|
||||||
// WordListVersion is the version of compiled in word list.
|
|
||||||
const WordListVersion = "0.7"
|
|
||||||
|
|
||||||
var wordMap = make(map[string]int, len(WordList))
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
for i, w := range WordList {
|
|
||||||
wordMap[w] = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const longestWord = 7
|
|
||||||
|
|
||||||
var WordList = []string{
|
|
||||||
"academy", "acrobat", "active", "actor", "adam", "admiral",
|
|
||||||
"adrian", "africa", "agenda", "agent", "airline", "airport",
|
|
||||||
"aladdin", "alarm", "alaska", "albert", "albino", "album",
|
|
||||||
"alcohol", "alex", "algebra", "alibi", "alice", "alien",
|
|
||||||
"alpha", "alpine", "amadeus", "amanda", "amazon", "amber",
|
|
||||||
"america", "amigo", "analog", "anatomy", "angel", "animal",
|
|
||||||
"antenna", "antonio", "apollo", "april", "archive", "arctic",
|
|
||||||
"arizona", "arnold", "aroma", "arthur", "artist", "asia",
|
|
||||||
"aspect", "aspirin", "athena", "athlete", "atlas", "audio",
|
|
||||||
"august", "austria", "axiom", "aztec", "balance", "ballad",
|
|
||||||
"banana", "bandit", "banjo", "barcode", "baron", "basic",
|
|
||||||
"battery", "belgium", "berlin", "bermuda", "bernard", "bikini",
|
|
||||||
"binary", "bingo", "biology", "block", "blonde", "bonus",
|
|
||||||
"boris", "boston", "boxer", "brandy", "bravo", "brazil",
|
|
||||||
"bronze", "brown", "bruce", "bruno", "burger", "burma",
|
|
||||||
"cabinet", "cactus", "cafe", "cairo", "cake", "calypso",
|
|
||||||
"camel", "camera", "campus", "canada", "canal", "cannon",
|
|
||||||
"canoe", "cantina", "canvas", "canyon", "capital", "caramel",
|
|
||||||
"caravan", "carbon", "cargo", "carlo", "carol", "carpet",
|
|
||||||
"cartel", "casino", "castle", "castro", "catalog", "caviar",
|
|
||||||
"cecilia", "cement", "center", "century", "ceramic", "chamber",
|
|
||||||
"chance", "change", "chaos", "charlie", "charm", "charter",
|
|
||||||
"chef", "chemist", "cherry", "chess", "chicago", "chicken",
|
|
||||||
"chief", "china", "cigar", "cinema", "circus", "citizen",
|
|
||||||
"city", "clara", "classic", "claudia", "clean", "client",
|
|
||||||
"climax", "clinic", "clock", "club", "cobra", "coconut",
|
|
||||||
"cola", "collect", "colombo", "colony", "color", "combat",
|
|
||||||
"comedy", "comet", "command", "compact", "company", "complex",
|
|
||||||
"concept", "concert", "connect", "consul", "contact", "context",
|
|
||||||
"contour", "control", "convert", "copy", "corner", "corona",
|
|
||||||
"correct", "cosmos", "couple", "courage", "cowboy", "craft",
|
|
||||||
"crash", "credit", "cricket", "critic", "crown", "crystal",
|
|
||||||
"cuba", "culture", "dallas", "dance", "daniel", "david",
|
|
||||||
"decade", "decimal", "deliver", "delta", "deluxe", "demand",
|
|
||||||
"demo", "denmark", "derby", "design", "detect", "develop",
|
|
||||||
"diagram", "dialog", "diamond", "diana", "diego", "diesel",
|
|
||||||
"diet", "digital", "dilemma", "diploma", "direct", "disco",
|
|
||||||
"disney", "distant", "doctor", "dollar", "dominic", "domino",
|
|
||||||
"donald", "dragon", "drama", "dublin", "duet", "dynamic",
|
|
||||||
"east", "ecology", "economy", "edgar", "egypt", "elastic",
|
|
||||||
"elegant", "element", "elite", "elvis", "email", "energy",
|
|
||||||
"engine", "english", "episode", "equator", "escort", "ethnic",
|
|
||||||
"europe", "everest", "evident", "exact", "example", "exit",
|
|
||||||
"exotic", "export", "express", "extra", "fabric", "factor",
|
|
||||||
"falcon", "family", "fantasy", "fashion", "fiber", "fiction",
|
|
||||||
"fidel", "fiesta", "figure", "film", "filter", "final",
|
|
||||||
"finance", "finish", "finland", "flash", "florida", "flower",
|
|
||||||
"fluid", "flute", "focus", "ford", "forest", "formal",
|
|
||||||
"format", "formula", "fortune", "forum", "fragile", "france",
|
|
||||||
"frank", "friend", "frozen", "future", "gabriel", "galaxy",
|
|
||||||
"gallery", "gamma", "garage", "garden", "garlic", "gemini",
|
|
||||||
"general", "genetic", "genius", "germany", "global", "gloria",
|
|
||||||
"golf", "gondola", "gong", "good", "gordon", "gorilla",
|
|
||||||
"grand", "granite", "graph", "green", "group", "guide",
|
|
||||||
"guitar", "guru", "hand", "happy", "harbor", "harmony",
|
|
||||||
"harvard", "havana", "hawaii", "helena", "hello", "henry",
|
|
||||||
"hilton", "history", "horizon", "hotel", "human", "humor",
|
|
||||||
"icon", "idea", "igloo", "igor", "image", "impact",
|
|
||||||
"import", "index", "india", "indigo", "input", "insect",
|
|
||||||
"instant", "iris", "italian", "jacket", "jacob", "jaguar",
|
|
||||||
"janet", "japan", "jargon", "jazz", "jeep", "john",
|
|
||||||
"joker", "jordan", "jumbo", "june", "jungle", "junior",
|
|
||||||
"jupiter", "karate", "karma", "kayak", "kermit", "kilo",
|
|
||||||
"king", "koala", "korea", "labor", "lady", "lagoon",
|
|
||||||
"laptop", "laser", "latin", "lava", "lecture", "left",
|
|
||||||
"legal", "lemon", "level", "lexicon", "liberal", "libra",
|
|
||||||
"limbo", "limit", "linda", "linear", "lion", "liquid",
|
|
||||||
"liter", "little", "llama", "lobby", "lobster", "local",
|
|
||||||
"logic", "logo", "lola", "london", "lotus", "lucas",
|
|
||||||
"lunar", "machine", "macro", "madam", "madonna", "madrid",
|
|
||||||
"maestro", "magic", "magnet", "magnum", "major", "mama",
|
|
||||||
"mambo", "manager", "mango", "manila", "marco", "marina",
|
|
||||||
"market", "mars", "martin", "marvin", "master", "matrix",
|
|
||||||
"maximum", "media", "medical", "mega", "melody", "melon",
|
|
||||||
"memo", "mental", "mentor", "menu", "mercury", "message",
|
|
||||||
"metal", "meteor", "meter", "method", "metro", "mexico",
|
|
||||||
"miami", "micro", "million", "mineral", "minimum", "minus",
|
|
||||||
"minute", "miracle", "mirage", "miranda", "mister", "mixer",
|
|
||||||
"mobile", "model", "modem", "modern", "modular", "moment",
|
|
||||||
"monaco", "monica", "monitor", "mono", "monster", "montana",
|
|
||||||
"morgan", "motel", "motif", "motor", "mozart", "multi",
|
|
||||||
"museum", "music", "mustang", "natural", "neon", "nepal",
|
|
||||||
"neptune", "nerve", "neutral", "nevada", "news", "ninja",
|
|
||||||
"nirvana", "normal", "nova", "novel", "nuclear", "numeric",
|
|
||||||
"nylon", "oasis", "object", "observe", "ocean", "octopus",
|
|
||||||
"olivia", "olympic", "omega", "opera", "optic", "optimal",
|
|
||||||
"orange", "orbit", "organic", "orient", "origin", "orlando",
|
|
||||||
"oscar", "oxford", "oxygen", "ozone", "pablo", "pacific",
|
|
||||||
"pagoda", "palace", "pamela", "panama", "panda", "panel",
|
|
||||||
"panic", "paradox", "pardon", "paris", "parker", "parking",
|
|
||||||
"parody", "partner", "passage", "passive", "pasta", "pastel",
|
|
||||||
"patent", "patriot", "patrol", "patron", "pegasus", "pelican",
|
|
||||||
"penguin", "pepper", "percent", "perfect", "perfume", "period",
|
|
||||||
"permit", "person", "peru", "phone", "photo", "piano",
|
|
||||||
"picasso", "picnic", "picture", "pigment", "pilgrim", "pilot",
|
|
||||||
"pirate", "pixel", "pizza", "planet", "plasma", "plaster",
|
|
||||||
"plastic", "plaza", "pocket", "poem", "poetic", "poker",
|
|
||||||
"polaris", "police", "politic", "polo", "polygon", "pony",
|
|
||||||
"popcorn", "popular", "postage", "postal", "precise", "prefix",
|
|
||||||
"premium", "present", "price", "prince", "printer", "prism",
|
|
||||||
"private", "product", "profile", "program", "project", "protect",
|
|
||||||
"proton", "public", "pulse", "puma", "pyramid", "queen",
|
|
||||||
"radar", "radio", "random", "rapid", "rebel", "record",
|
|
||||||
"recycle", "reflex", "reform", "regard", "regular", "relax",
|
|
||||||
"report", "reptile", "reverse", "ricardo", "ringo", "ritual",
|
|
||||||
"robert", "robot", "rocket", "rodeo", "romeo", "royal",
|
|
||||||
"russian", "safari", "salad", "salami", "salmon", "salon",
|
|
||||||
"salute", "samba", "sandra", "santana", "sardine", "school",
|
|
||||||
"screen", "script", "second", "secret", "section", "segment",
|
|
||||||
"select", "seminar", "senator", "senior", "sensor", "serial",
|
|
||||||
"service", "sheriff", "shock", "sierra", "signal", "silicon",
|
|
||||||
"silver", "similar", "simon", "single", "siren", "slogan",
|
|
||||||
"social", "soda", "solar", "solid", "solo", "sonic",
|
|
||||||
"soviet", "special", "speed", "spiral", "spirit", "sport",
|
|
||||||
"static", "station", "status", "stereo", "stone", "stop",
|
|
||||||
"street", "strong", "student", "studio", "style", "subject",
|
|
||||||
"sultan", "super", "susan", "sushi", "suzuki", "switch",
|
|
||||||
"symbol", "system", "tactic", "tahiti", "talent", "tango",
|
|
||||||
"tarzan", "taxi", "telex", "tempo", "tennis", "texas",
|
|
||||||
"textile", "theory", "thermos", "tiger", "titanic", "tokyo",
|
|
||||||
"tomato", "topic", "tornado", "toronto", "torpedo", "total",
|
|
||||||
"totem", "tourist", "tractor", "traffic", "transit", "trapeze",
|
|
||||||
"travel", "tribal", "trick", "trident", "trilogy", "tripod",
|
|
||||||
"tropic", "trumpet", "tulip", "tuna", "turbo", "twist",
|
|
||||||
"ultra", "uniform", "union", "uranium", "vacuum", "valid",
|
|
||||||
"vampire", "vanilla", "vatican", "velvet", "ventura", "venus",
|
|
||||||
"vertigo", "veteran", "victor", "video", "vienna", "viking",
|
|
||||||
"village", "vincent", "violet", "violin", "virtual", "virus",
|
|
||||||
"visa", "vision", "visitor", "visual", "vitamin", "viva",
|
|
||||||
"vocal", "vodka", "volcano", "voltage", "volume", "voyage",
|
|
||||||
"water", "weekend", "welcome", "western", "window", "winter",
|
|
||||||
"wizard", "wolf", "world", "xray", "yankee", "yoga",
|
|
||||||
"yogurt", "yoyo", "zebra", "zero", "zigzag", "zipper",
|
|
||||||
"zodiac", "zoom", "abraham", "action", "address", "alabama",
|
|
||||||
"alfred", "almond", "ammonia", "analyze", "annual", "answer",
|
|
||||||
"apple", "arena", "armada", "arsenal", "atlanta", "atomic",
|
|
||||||
"avenue", "average", "bagel", "baker", "ballet", "bambino",
|
|
||||||
"bamboo", "barbara", "basket", "bazaar", "benefit", "bicycle",
|
|
||||||
"bishop", "blitz", "bonjour", "bottle", "bridge", "british",
|
|
||||||
"brother", "brush", "budget", "cabaret", "cadet", "candle",
|
|
||||||
"capitan", "capsule", "career", "cartoon", "channel", "chapter",
|
|
||||||
"cheese", "circle", "cobalt", "cockpit", "college", "compass",
|
|
||||||
"comrade", "condor", "crimson", "cyclone", "darwin", "declare",
|
|
||||||
"degree", "delete", "delphi", "denver", "desert", "divide",
|
|
||||||
"dolby", "domain", "domingo", "double", "drink", "driver",
|
|
||||||
"eagle", "earth", "echo", "eclipse", "editor", "educate",
|
|
||||||
"edward", "effect", "electra", "emerald", "emotion", "empire",
|
|
||||||
"empty", "escape", "eternal", "evening", "exhibit", "expand",
|
|
||||||
"explore", "extreme", "ferrari", "first", "flag", "folio",
|
|
||||||
"forget", "forward", "freedom", "fresh", "friday", "fuji",
|
|
||||||
"galileo", "garcia", "genesis", "gold", "gravity", "habitat",
|
|
||||||
"hamlet", "harlem", "helium", "holiday", "house", "hunter",
|
|
||||||
"ibiza", "iceberg", "imagine", "infant", "isotope", "jackson",
|
|
||||||
"jamaica", "jasmine", "java", "jessica", "judo", "kitchen",
|
|
||||||
"lazarus", "letter", "license", "lithium", "loyal", "lucky",
|
|
||||||
"magenta", "mailbox", "manual", "marble", "mary", "maxwell",
|
|
||||||
"mayor", "milk", "monarch", "monday", "money", "morning",
|
|
||||||
"mother", "mystery", "native", "nectar", "nelson", "network",
|
|
||||||
"next", "nikita", "nobel", "nobody", "nominal", "norway",
|
|
||||||
"nothing", "number", "october", "office", "oliver", "opinion",
|
|
||||||
"option", "order", "outside", "package", "pancake", "pandora",
|
|
||||||
"panther", "papa", "patient", "pattern", "pedro", "pencil",
|
|
||||||
"people", "phantom", "philips", "pioneer", "pluto", "podium",
|
|
||||||
"portal", "potato", "prize", "process", "protein", "proxy",
|
|
||||||
"pump", "pupil", "python", "quality", "quarter", "quiet",
|
|
||||||
"rabbit", "radical", "radius", "rainbow", "ralph", "ramirez",
|
|
||||||
"ravioli", "raymond", "respect", "respond", "result", "resume",
|
|
||||||
"retro", "richard", "right", "risk", "river", "roger",
|
|
||||||
"roman", "rondo", "sabrina", "salary", "salsa", "sample",
|
|
||||||
"samuel", "saturn", "savage", "scarlet", "scoop", "scorpio",
|
|
||||||
"scratch", "scroll", "sector", "serpent", "shadow", "shampoo",
|
|
||||||
"sharon", "sharp", "short", "shrink", "silence", "silk",
|
|
||||||
"simple", "slang", "smart", "smoke", "snake", "society",
|
|
||||||
"sonar", "sonata", "soprano", "source", "sparta", "sphere",
|
|
||||||
"spider", "sponsor", "spring", "acid", "adios", "agatha",
|
|
||||||
"alamo", "alert", "almanac", "aloha", "andrea", "anita",
|
|
||||||
"arcade", "aurora", "avalon", "baby", "baggage", "balloon",
|
|
||||||
"bank", "basil", "begin", "biscuit", "blue", "bombay",
|
|
||||||
"brain", "brenda", "brigade", "cable", "carmen", "cello",
|
|
||||||
"celtic", "chariot", "chrome", "citrus", "civil", "cloud",
|
|
||||||
"common", "compare", "cool", "copper", "coral", "crater",
|
|
||||||
"cubic", "cupid", "cycle", "depend", "door", "dream",
|
|
||||||
"dynasty", "edison", "edition", "enigma", "equal", "eric",
|
|
||||||
"event", "evita", "exodus", "extend", "famous", "farmer",
|
|
||||||
"food", "fossil", "frog", "fruit", "geneva", "gentle",
|
|
||||||
"george", "giant", "gilbert", "gossip", "gram", "greek",
|
|
||||||
"grille", "hammer", "harvest", "hazard", "heaven", "herbert",
|
|
||||||
"heroic", "hexagon", "husband", "immune", "inca", "inch",
|
|
||||||
"initial", "isabel", "ivory", "jason", "jerome", "joel",
|
|
||||||
"joshua", "journal", "judge", "juliet", "jump", "justice",
|
|
||||||
"kimono", "kinetic", "leonid", "lima", "maze", "medusa",
|
|
||||||
"member", "memphis", "michael", "miguel", "milan", "mile",
|
|
||||||
"miller", "mimic", "mimosa", "mission", "monkey", "moral",
|
|
||||||
"moses", "mouse", "nancy", "natasha", "nebula", "nickel",
|
|
||||||
"nina", "noise", "orchid", "oregano", "origami", "orinoco",
|
|
||||||
"orion", "othello", "paper", "paprika", "prelude", "prepare",
|
|
||||||
"pretend", "profit", "promise", "provide", "puzzle", "remote",
|
|
||||||
"repair", "reply", "rival", "riviera", "robin", "rose",
|
|
||||||
"rover", "rudolf", "saga", "sahara", "scholar", "shelter",
|
|
||||||
"ship", "shoe", "sigma", "sister", "sleep", "smile",
|
|
||||||
"spain", "spark", "split", "spray", "square", "stadium",
|
|
||||||
"star", "storm", "story", "strange", "stretch", "stuart",
|
|
||||||
"subway", "sugar", "sulfur", "summer", "survive", "sweet",
|
|
||||||
"swim", "table", "taboo", "target", "teacher", "telecom",
|
|
||||||
"temple", "tibet", "ticket", "tina", "today", "toga",
|
|
||||||
"tommy", "tower", "trivial", "tunnel", "turtle", "twin",
|
|
||||||
"uncle", "unicorn", "unique", "update", "valery", "vega",
|
|
||||||
"version", "voodoo", "warning", "william", "wonder", "year",
|
|
||||||
"yellow", "young", "absent", "absorb", "accent", "alfonso",
|
|
||||||
"alias", "ambient", "andy", "anvil", "appear", "apropos",
|
|
||||||
"archer", "ariel", "armor", "arrow", "austin", "avatar",
|
|
||||||
"axis", "baboon", "bahama", "bali", "balsa", "bazooka",
|
|
||||||
"beach", "beast", "beatles", "beauty", "before", "benny",
|
|
||||||
"betty", "between", "beyond", "billy", "bison", "blast",
|
|
||||||
"bless", "bogart", "bonanza", "book", "border", "brave",
|
|
||||||
"bread", "break", "broken", "bucket", "buenos", "buffalo",
|
|
||||||
"bundle", "button", "buzzer", "byte", "caesar", "camilla",
|
|
||||||
"canary", "candid", "carrot", "cave", "chant", "child",
|
|
||||||
"choice", "chris", "cipher", "clarion", "clark", "clever",
|
|
||||||
"cliff", "clone", "conan", "conduct", "congo", "content",
|
|
||||||
"costume", "cotton", "cover", "crack", "current", "danube",
|
|
||||||
"data", "decide", "desire", "detail", "dexter", "dinner",
|
|
||||||
"dispute", "donor", "druid", "drum", "easy", "eddie",
|
|
||||||
"enjoy", "enrico", "epoxy", "erosion", "except", "exile",
|
|
||||||
"explain", "fame", "fast", "father", "felix", "field",
|
|
||||||
"fiona", "fire", "fish", "flame", "flex", "flipper",
|
|
||||||
"float", "flood", "floor", "forbid", "forever", "fractal",
|
|
||||||
"frame", "freddie", "front", "fuel", "gallop", "game",
|
|
||||||
"garbo", "gate", "gibson", "ginger", "giraffe", "gizmo",
|
|
||||||
"glass", "goblin", "gopher", "grace", "gray", "gregory",
|
|
||||||
"grid", "griffin", "ground", "guest", "gustav", "gyro",
|
|
||||||
"hair", "halt", "harris", "heart", "heavy", "herman",
|
|
||||||
"hippie", "hobby", "honey", "hope", "horse", "hostel",
|
|
||||||
"hydro", "imitate", "info", "ingrid", "inside", "invent",
|
|
||||||
"invest", "invite", "iron", "ivan", "james", "jester",
|
|
||||||
"jimmy", "join", "joseph", "juice", "julius", "july",
|
|
||||||
"justin", "kansas", "karl", "kevin", "kiwi", "ladder",
|
|
||||||
"lake", "laura", "learn", "legacy", "legend", "lesson",
|
|
||||||
"life", "light", "list", "locate", "lopez", "lorenzo",
|
|
||||||
"love", "lunch", "malta", "mammal", "margo", "marion",
|
|
||||||
"mask", "match", "mayday", "meaning", "mercy", "middle",
|
|
||||||
"mike", "mirror", "modest", "morph", "morris", "nadia",
|
|
||||||
"nato", "navy", "needle", "neuron", "never", "newton",
|
|
||||||
"nice", "night", "nissan", "nitro", "nixon", "north",
|
|
||||||
"oberon", "octavia", "ohio", "olga", "open", "opus",
|
|
||||||
"orca", "oval", "owner", "page", "paint", "palma",
|
|
||||||
"parade", "parent", "parole", "paul", "peace", "pearl",
|
|
||||||
"perform", "phoenix", "phrase", "pierre", "pinball", "place",
|
|
||||||
"plate", "plato", "plume", "pogo", "point", "polite",
|
|
||||||
"polka", "poncho", "powder", "prague", "press", "presto",
|
|
||||||
"pretty", "prime", "promo", "quasi", "quest", "quick",
|
|
||||||
"quiz", "quota", "race", "rachel", "raja", "ranger",
|
|
||||||
"region", "remark", "rent", "reward", "rhino", "ribbon",
|
|
||||||
"rider", "road", "rodent", "round", "rubber", "ruby",
|
|
||||||
"rufus", "sabine", "saddle", "sailor", "saint", "salt",
|
|
||||||
"satire", "scale", "scuba", "season", "secure", "shake",
|
|
||||||
"shallow", "shannon", "shave", "shelf", "sherman", "shine",
|
|
||||||
"shirt", "side", "sinatra", "sincere", "size", "slalom",
|
|
||||||
"slow", "small", "snow", "sofia", "song", "sound",
|
|
||||||
"south", "speech", "spell", "spend", "spoon", "stage",
|
|
||||||
"stamp", "stand", "state", "stella", "stick", "sting",
|
|
||||||
"stock", "store", "sunday", "sunset", "support", "sweden",
|
|
||||||
"swing", "tape", "think", "thomas", "tictac", "time",
|
|
||||||
"toast", "tobacco", "tonight", "torch", "torso", "touch",
|
|
||||||
"toyota", "trade", "tribune", "trinity", "triton", "truck",
|
|
||||||
"trust", "type", "under", "unit", "urban", "urgent",
|
|
||||||
"user", "value", "vendor", "venice", "verona", "vibrate",
|
|
||||||
"virgo", "visible", "vista", "vital", "voice", "vortex",
|
|
||||||
"waiter", "watch", "wave", "weather", "wedding", "wheel",
|
|
||||||
"whiskey", "wisdom", "deal", "null", "nurse", "quebec",
|
|
||||||
"reserve", "reunion", "roof", "singer", "verbal", "amen",
|
|
||||||
"ego", "fax", "jet", "job", "rio", "ski",
|
|
||||||
"yes",
|
|
||||||
}
|
|
||||||
|
|
@ -6,10 +6,8 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/schollz/croc/v10/src/utils"
|
"github.com/schollz/croc/v9/src/utils"
|
||||||
log "github.com/schollz/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TCP_BUFFER_SIZE is the maximum packet size
|
// TCP_BUFFER_SIZE is the maximum packet size
|
||||||
|
|
@ -56,8 +54,6 @@ func getConfigFile(requireValidPath bool) (fname string, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
log.SetLevel("info")
|
|
||||||
log.SetOutput(os.Stderr)
|
|
||||||
doRemember := false
|
doRemember := false
|
||||||
for _, flag := range os.Args {
|
for _, flag := range os.Args {
|
||||||
if flag == "--internal-dns" {
|
if flag == "--internal-dns" {
|
||||||
|
|
@ -82,7 +78,6 @@ func init() {
|
||||||
INTERNAL_DNS = utils.Exists(fname)
|
INTERNAL_DNS = utils.Exists(fname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Trace("Using internal DNS: ", INTERNAL_DNS)
|
|
||||||
var err error
|
var err error
|
||||||
var addr string
|
var addr string
|
||||||
addr, err = lookup(DEFAULT_RELAY)
|
addr, err = lookup(DEFAULT_RELAY)
|
||||||
|
|
@ -91,20 +86,17 @@ func init() {
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_RELAY = ""
|
DEFAULT_RELAY = ""
|
||||||
}
|
}
|
||||||
log.Tracef("Default ipv4 relay: %s", addr)
|
|
||||||
addr, err = lookup(DEFAULT_RELAY6)
|
addr, err = lookup(DEFAULT_RELAY6)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
DEFAULT_RELAY6 = net.JoinHostPort(addr, DEFAULT_PORT)
|
DEFAULT_RELAY6 = net.JoinHostPort(addr, DEFAULT_PORT)
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_RELAY6 = ""
|
DEFAULT_RELAY6 = ""
|
||||||
}
|
}
|
||||||
log.Tracef("Default ipv6 relay: %s", addr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve a hostname to an IP address using DNS.
|
// Resolve a hostname to an IP address using DNS.
|
||||||
func lookup(address string) (ipaddress string, err error) {
|
func lookup(address string) (ipaddress string, err error) {
|
||||||
if !INTERNAL_DNS {
|
if !INTERNAL_DNS {
|
||||||
log.Tracef("Using local DNS to resolve %s", address)
|
|
||||||
return localLookupIP(address)
|
return localLookupIP(address)
|
||||||
}
|
}
|
||||||
type Result struct {
|
type Result struct {
|
||||||
|
|
@ -116,13 +108,11 @@ func lookup(address string) (ipaddress string, err error) {
|
||||||
go func(dns string) {
|
go func(dns string) {
|
||||||
var r Result
|
var r Result
|
||||||
r.s, r.err = remoteLookupIP(address, dns)
|
r.s, r.err = remoteLookupIP(address, dns)
|
||||||
log.Tracef("Resolved %s to %s using %s", address, r.s, dns)
|
|
||||||
result <- r
|
result <- r
|
||||||
}(dns)
|
}(dns)
|
||||||
}
|
}
|
||||||
for i := 0; i < len(publicDNS); i++ {
|
for i := 0; i < len(publicDNS); i++ {
|
||||||
ipaddress = (<-result).s
|
ipaddress = (<-result).s
|
||||||
log.Tracef("Resolved %s to %s", address, ipaddress)
|
|
||||||
if ipaddress != "" {
|
if ipaddress != "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -131,16 +121,9 @@ func lookup(address string) (ipaddress string, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// localLookupIP returns a host's IP address using the local DNS configuration.
|
// localLookupIP returns a host's IP address based on the local resolver.
|
||||||
func localLookupIP(address string) (ipaddress string, err error) {
|
func localLookupIP(address string) (ipaddress string, err error) {
|
||||||
// Create a context with a 500 millisecond timeout
|
ip, err := net.LookupHost(address)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
r := &net.Resolver{}
|
|
||||||
|
|
||||||
// Use the context with timeout in the LookupHost function
|
|
||||||
ip, err := r.LookupHost(ctx, address)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -150,9 +133,6 @@ func localLookupIP(address string) (ipaddress string, err error) {
|
||||||
|
|
||||||
// remoteLookupIP returns a host's IP address based on a remote DNS server.
|
// remoteLookupIP returns a host's IP address based on a remote DNS server.
|
||||||
func remoteLookupIP(address, dns string) (ipaddress string, err error) {
|
func remoteLookupIP(address, dns string) (ipaddress string, err error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
r := &net.Resolver{
|
r := &net.Resolver{
|
||||||
PreferGo: true,
|
PreferGo: true,
|
||||||
Dial: func(ctx context.Context, network, _ string) (net.Conn, error) {
|
Dial: func(ctx context.Context, network, _ string) (net.Conn, error) {
|
||||||
|
|
@ -160,7 +140,7 @@ func remoteLookupIP(address, dns string) (ipaddress string, err error) {
|
||||||
return d.DialContext(ctx, network, dns+":53")
|
return d.DialContext(ctx, network, dns+":53")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ip, err := r.LookupHost(ctx, address)
|
ip, err := r.LookupHost(context.Background(), address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 70 KiB |
|
|
@ -1,9 +0,0 @@
|
||||||
package tcp
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
const (
|
|
||||||
DEFAULT_LOG_LEVEL = "debug"
|
|
||||||
DEFAULT_ROOM_CLEANUP_INTERVAL = 10 * time.Minute
|
|
||||||
DEFAULT_ROOM_TTL = 3 * time.Hour
|
|
||||||
)
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
package tcp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: maybe export from logger library?
|
|
||||||
var availableLogLevels = []string{"info", "error", "warn", "debug", "trace"}
|
|
||||||
|
|
||||||
type serverOptsFunc func(s *server) error
|
|
||||||
|
|
||||||
func WithBanner(banner ...string) serverOptsFunc {
|
|
||||||
return func(s *server) error {
|
|
||||||
if len(banner) > 0 {
|
|
||||||
s.banner = banner[0]
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithLogLevel(level string) serverOptsFunc {
|
|
||||||
return func(s *server) error {
|
|
||||||
if !containsSlice(availableLogLevels, level) {
|
|
||||||
return fmt.Errorf("invalid log level specified: %s", level)
|
|
||||||
}
|
|
||||||
s.debugLevel = level
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithRoomCleanupInterval(interval time.Duration) serverOptsFunc {
|
|
||||||
return func(s *server) error {
|
|
||||||
s.roomCleanupInterval = interval
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithRoomTTL(ttl time.Duration) serverOptsFunc {
|
|
||||||
return func(s *server) error {
|
|
||||||
s.roomTTL = ttl
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsSlice(s []string, e string) bool {
|
|
||||||
for _, ss := range s {
|
|
||||||
if e == ss {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
107
src/tcp/tcp.go
107
src/tcp/tcp.go
|
|
@ -11,9 +11,9 @@ import (
|
||||||
log "github.com/schollz/logger"
|
log "github.com/schollz/logger"
|
||||||
"github.com/schollz/pake/v3"
|
"github.com/schollz/pake/v3"
|
||||||
|
|
||||||
"github.com/schollz/croc/v10/src/comm"
|
"github.com/schollz/croc/v9/src/comm"
|
||||||
"github.com/schollz/croc/v10/src/crypt"
|
"github.com/schollz/croc/v9/src/crypt"
|
||||||
"github.com/schollz/croc/v10/src/models"
|
"github.com/schollz/croc/v9/src/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
type server struct {
|
type server struct {
|
||||||
|
|
@ -23,11 +23,6 @@ type server struct {
|
||||||
banner string
|
banner string
|
||||||
password string
|
password string
|
||||||
rooms roomMap
|
rooms roomMap
|
||||||
|
|
||||||
roomCleanupInterval time.Duration
|
|
||||||
roomTTL time.Duration
|
|
||||||
|
|
||||||
stopRoomCleanup chan struct{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type roomInfo struct {
|
type roomInfo struct {
|
||||||
|
|
@ -44,55 +39,46 @@ type roomMap struct {
|
||||||
|
|
||||||
const pingRoom = "pinglkasjdlfjsaldjf"
|
const pingRoom = "pinglkasjdlfjsaldjf"
|
||||||
|
|
||||||
// newDefaultServer initializes a new server, with some default configuration options
|
var timeToRoomDeletion = 10 * time.Minute
|
||||||
func newDefaultServer() *server {
|
|
||||||
s := new(server)
|
|
||||||
s.roomCleanupInterval = DEFAULT_ROOM_CLEANUP_INTERVAL
|
|
||||||
s.roomTTL = DEFAULT_ROOM_TTL
|
|
||||||
s.debugLevel = DEFAULT_LOG_LEVEL
|
|
||||||
s.stopRoomCleanup = make(chan struct{})
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunWithOptionsAsync asynchronously starts a TCP listener.
|
// Run starts a tcp listener, run async
|
||||||
func RunWithOptionsAsync(host, port, password string, opts ...serverOptsFunc) error {
|
func Run(debugLevel, host, port, password string, banner ...string) (err error) {
|
||||||
s := newDefaultServer()
|
s := new(server)
|
||||||
s.host = host
|
s.host = host
|
||||||
s.port = port
|
s.port = port
|
||||||
s.password = password
|
s.password = password
|
||||||
for _, opt := range opts {
|
s.debugLevel = debugLevel
|
||||||
err := opt(s)
|
if len(banner) > 0 {
|
||||||
if err != nil {
|
s.banner = banner[0]
|
||||||
return fmt.Errorf("could not apply optional configurations: %w", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return s.start()
|
return s.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts a tcp listener, run async
|
|
||||||
func Run(debugLevel, host, port, password string, banner ...string) (err error) {
|
|
||||||
return RunWithOptionsAsync(host, port, password, WithBanner(banner...), WithLogLevel(debugLevel))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *server) start() (err error) {
|
func (s *server) start() (err error) {
|
||||||
log.SetLevel(s.debugLevel)
|
log.SetLevel(s.debugLevel)
|
||||||
|
log.Debugf("starting with password '%s'", s.password)
|
||||||
// Mask our password in logs
|
|
||||||
maskedPassword := ""
|
|
||||||
if len(s.password) > 2 {
|
|
||||||
maskedPassword = fmt.Sprintf("%c***%c", s.password[0], s.password[len(s.password)-1])
|
|
||||||
} else {
|
|
||||||
maskedPassword = s.password
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("starting with password '%s'", maskedPassword)
|
|
||||||
|
|
||||||
s.rooms.Lock()
|
s.rooms.Lock()
|
||||||
s.rooms.rooms = make(map[string]roomInfo)
|
s.rooms.rooms = make(map[string]roomInfo)
|
||||||
s.rooms.Unlock()
|
s.rooms.Unlock()
|
||||||
|
|
||||||
go s.deleteOldRooms()
|
// delete old rooms
|
||||||
defer s.stopRoomDeletion()
|
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()
|
err = s.run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -187,39 +173,6 @@ func (s *server) run() (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteOldRooms checks for rooms at a regular interval and removes those that
|
|
||||||
// have exceeded their allocated TTL.
|
|
||||||
func (s *server) deleteOldRooms() {
|
|
||||||
ticker := time.NewTicker(s.roomCleanupInterval)
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
var roomsToDelete []string
|
|
||||||
s.rooms.Lock()
|
|
||||||
for room := range s.rooms.rooms {
|
|
||||||
if time.Since(s.rooms.rooms[room].opened) > s.roomTTL {
|
|
||||||
roomsToDelete = append(roomsToDelete, room)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.rooms.Unlock()
|
|
||||||
|
|
||||||
for _, room := range roomsToDelete {
|
|
||||||
s.deleteRoom(room)
|
|
||||||
log.Debugf("room cleaned up: %s", room)
|
|
||||||
}
|
|
||||||
case <-s.stopRoomCleanup:
|
|
||||||
ticker.Stop()
|
|
||||||
log.Debug("room cleanup stopped")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *server) stopRoomDeletion() {
|
|
||||||
log.Debug("stop room cleanup fired")
|
|
||||||
s.stopRoomCleanup <- struct{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var weakKey = []byte{1, 2, 3}
|
var weakKey = []byte{1, 2, 3}
|
||||||
|
|
||||||
func (s *server) clientCommunication(port string, c *comm.Comm) (room string, err error) {
|
func (s *server) clientCommunication(port string, c *comm.Comm) (room string, err error) {
|
||||||
|
|
@ -563,7 +516,7 @@ func ConnectToTCPServer(address, password, room string, timelimit ...time.Durati
|
||||||
}
|
}
|
||||||
banner = strings.Split(string(data), "|||")[0]
|
banner = strings.Split(string(data), "|||")[0]
|
||||||
ipaddr = strings.Split(string(data), "|||")[1]
|
ipaddr = strings.Split(string(data), "|||")[1]
|
||||||
log.Debugf("sending room; %s", room)
|
log.Debug("sending room")
|
||||||
bSend, err = crypt.Encrypt([]byte(room), strongKeyForEncryption)
|
bSend, err = crypt.Encrypt([]byte(room), strongKeyForEncryption)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ func BenchmarkConnection(b *testing.B) {
|
||||||
|
|
||||||
func TestTCP(t *testing.T) {
|
func TestTCP(t *testing.T) {
|
||||||
log.SetLevel("error")
|
log.SetLevel("error")
|
||||||
timeToRoomDeletion := 100 * time.Millisecond
|
timeToRoomDeletion = 100 * time.Millisecond
|
||||||
go RunWithOptionsAsync("127.0.0.1", "8381", "pass123", WithBanner("8382"), WithLogLevel("debug"), WithRoomTTL(timeToRoomDeletion))
|
go Run("debug", "127.0.0.1", "8381", "pass123", "8382")
|
||||||
time.Sleep(timeToRoomDeletion)
|
time.Sleep(timeToRoomDeletion)
|
||||||
err := PingServer("127.0.0.1:8381")
|
err := PingServer("127.0.0.1:8381")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
|
|
@ -20,14 +21,10 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"github.com/cespare/xxhash"
|
"github.com/cespare/xxhash"
|
||||||
"github.com/kalafut/imohash"
|
"github.com/kalafut/imohash"
|
||||||
"github.com/minio/highwayhash"
|
"github.com/schollz/mnemonicode"
|
||||||
"github.com/schollz/croc/v10/src/mnemonicode"
|
|
||||||
log "github.com/schollz/logger"
|
|
||||||
"github.com/schollz/progressbar/v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const NbPinNumbers = 4
|
const NbPinNumbers = 4
|
||||||
|
|
@ -79,11 +76,7 @@ func GetInput(prompt string) string {
|
||||||
|
|
||||||
// HashFile returns the hash of a file or, in case of a symlink, the
|
// HashFile returns the hash of a file or, in case of a symlink, the
|
||||||
// SHA256 hash of its target. Takes an argument to specify the algorithm to use.
|
// SHA256 hash of its target. Takes an argument to specify the algorithm to use.
|
||||||
func HashFile(fname string, algorithm string, showProgress ...bool) (hash256 []byte, err error) {
|
func HashFile(fname string, algorithm string) (hash256 []byte, err error) {
|
||||||
doShowProgress := false
|
|
||||||
if len(showProgress) > 0 {
|
|
||||||
doShowProgress = showProgress[0]
|
|
||||||
}
|
|
||||||
var fstats os.FileInfo
|
var fstats os.FileInfo
|
||||||
fstats, err = os.Lstat(fname)
|
fstats, err = os.Lstat(fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -101,59 +94,16 @@ func HashFile(fname string, algorithm string, showProgress ...bool) (hash256 []b
|
||||||
case "imohash":
|
case "imohash":
|
||||||
return IMOHashFile(fname)
|
return IMOHashFile(fname)
|
||||||
case "md5":
|
case "md5":
|
||||||
return MD5HashFile(fname, doShowProgress)
|
return MD5HashFile(fname)
|
||||||
case "xxhash":
|
case "xxhash":
|
||||||
return XXHashFile(fname, doShowProgress)
|
return XXHashFile(fname)
|
||||||
case "highway":
|
|
||||||
return HighwayHashFile(fname, doShowProgress)
|
|
||||||
}
|
}
|
||||||
err = fmt.Errorf("unspecified algorithm")
|
err = fmt.Errorf("unspecified algorithm")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// HighwayHashFile returns highwayhash of a file
|
|
||||||
func HighwayHashFile(fname string, doShowProgress bool) (hashHighway []byte, err error) {
|
|
||||||
f, err := os.Open(fname)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
key, err := hex.DecodeString("1553c5383fb0b86578c3310da665b4f6e0521acf22eb58a99532ffed02a6b115")
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h, err := highwayhash.New(key)
|
|
||||||
if err != nil {
|
|
||||||
err = fmt.Errorf("could not create highwayhash: %s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if doShowProgress {
|
|
||||||
stat, _ := f.Stat()
|
|
||||||
fnameShort := path.Base(fname)
|
|
||||||
if len(fnameShort) > 20 {
|
|
||||||
fnameShort = fnameShort[:20] + "..."
|
|
||||||
}
|
|
||||||
bar := progressbar.NewOptions64(stat.Size(),
|
|
||||||
progressbar.OptionSetWriter(os.Stderr),
|
|
||||||
progressbar.OptionShowBytes(true),
|
|
||||||
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
|
|
||||||
progressbar.OptionClearOnFinish(),
|
|
||||||
)
|
|
||||||
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if _, err = io.Copy(h, f); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hashHighway = h.Sum(nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// MD5HashFile returns MD5 hash
|
// MD5HashFile returns MD5 hash
|
||||||
func MD5HashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
|
func MD5HashFile(fname string) (hash256 []byte, err error) {
|
||||||
f, err := os.Open(fname)
|
f, err := os.Open(fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -161,41 +111,23 @@ func MD5HashFile(fname string, doShowProgress bool) (hash256 []byte, err error)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
h := md5.New()
|
h := md5.New()
|
||||||
if doShowProgress {
|
if _, err = io.Copy(h, f); err != nil {
|
||||||
stat, _ := f.Stat()
|
return
|
||||||
fnameShort := path.Base(fname)
|
|
||||||
if len(fnameShort) > 20 {
|
|
||||||
fnameShort = fnameShort[:20] + "..."
|
|
||||||
}
|
|
||||||
bar := progressbar.NewOptions64(stat.Size(),
|
|
||||||
progressbar.OptionSetWriter(os.Stderr),
|
|
||||||
progressbar.OptionShowBytes(true),
|
|
||||||
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
|
|
||||||
progressbar.OptionClearOnFinish(),
|
|
||||||
)
|
|
||||||
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if _, err = io.Copy(h, f); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hash256 = h.Sum(nil)
|
hash256 = h.Sum(nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var imofull = imohash.NewCustom(0, 0)
|
|
||||||
var imopartial = imohash.NewCustom(16*16*8*1024, 128*1024)
|
|
||||||
|
|
||||||
// IMOHashFile returns imohash
|
// IMOHashFile returns imohash
|
||||||
func IMOHashFile(fname string) (hash []byte, err error) {
|
func IMOHashFile(fname string) (hash []byte, err error) {
|
||||||
b, err := imopartial.SumFile(fname)
|
b, err := imohash.SumFile(fname)
|
||||||
hash = b[:]
|
hash = b[:]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var imofull = imohash.NewCustom(0, 0)
|
||||||
|
|
||||||
// IMOHashFileFull returns imohash of full file
|
// IMOHashFileFull returns imohash of full file
|
||||||
func IMOHashFileFull(fname string) (hash []byte, err error) {
|
func IMOHashFileFull(fname string) (hash []byte, err error) {
|
||||||
b, err := imofull.SumFile(fname)
|
b, err := imofull.SumFile(fname)
|
||||||
|
|
@ -204,7 +136,7 @@ func IMOHashFileFull(fname string) (hash []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXHashFile returns the xxhash of a file
|
// XXHashFile returns the xxhash of a file
|
||||||
func XXHashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
|
func XXHashFile(fname string) (hash256 []byte, err error) {
|
||||||
f, err := os.Open(fname)
|
f, err := os.Open(fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
|
|
@ -212,25 +144,8 @@ func XXHashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
h := xxhash.New()
|
h := xxhash.New()
|
||||||
if doShowProgress {
|
if _, err = io.Copy(h, f); err != nil {
|
||||||
stat, _ := f.Stat()
|
return
|
||||||
fnameShort := path.Base(fname)
|
|
||||||
if len(fnameShort) > 20 {
|
|
||||||
fnameShort = fnameShort[:20] + "..."
|
|
||||||
}
|
|
||||||
bar := progressbar.NewOptions64(stat.Size(),
|
|
||||||
progressbar.OptionSetWriter(os.Stderr),
|
|
||||||
progressbar.OptionShowBytes(true),
|
|
||||||
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
|
|
||||||
progressbar.OptionClearOnFinish(),
|
|
||||||
)
|
|
||||||
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if _, err = io.Copy(h, f); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hash256 = h.Sum(nil)
|
hash256 = h.Sum(nil)
|
||||||
|
|
@ -246,21 +161,19 @@ func SHA256(s string) string {
|
||||||
|
|
||||||
// PublicIP returns public ip address
|
// PublicIP returns public ip address
|
||||||
func PublicIP() (ip string, err error) {
|
func PublicIP() (ip string, err error) {
|
||||||
// ask ipv4.icanhazip.com for the public ip
|
resp, err := http.Get("https://canhazip.com")
|
||||||
// by making http request
|
|
||||||
// if the request fails, return nothing
|
|
||||||
resp, err := http.Get("http://ipv4.icanhazip.com")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
// read the body of the response
|
if resp.StatusCode == http.StatusOK {
|
||||||
// and return the ip address
|
bodyBytes, err := io.ReadAll(resp.Body)
|
||||||
buf := new(bytes.Buffer)
|
if err != nil {
|
||||||
buf.ReadFrom(resp.Body)
|
return "", err
|
||||||
ip = strings.TrimSpace(buf.String())
|
}
|
||||||
|
ip = strings.TrimSpace(string(bodyBytes))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,8 +181,7 @@ func PublicIP() (ip string, err error) {
|
||||||
func LocalIP() string {
|
func LocalIP() string {
|
||||||
conn, err := net.Dial("udp", "8.8.8.8:80")
|
conn, err := net.Dial("udp", "8.8.8.8:80")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Fatal(err)
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
|
|
@ -470,12 +382,12 @@ func IsLocalIP(ipaddress string) bool {
|
||||||
|
|
||||||
func ZipDirectory(destination string, source string) (err error) {
|
func ZipDirectory(destination string, source string) (err error) {
|
||||||
if _, err = os.Stat(destination); err == nil {
|
if _, err = os.Stat(destination); err == nil {
|
||||||
log.Errorf("%s file already exists!\n", destination)
|
log.Fatalf("%s file already exists!\n", destination)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "Zipping %s to %s\n", source, destination)
|
fmt.Fprintf(os.Stderr, "Zipping %s to %s\n", source, destination)
|
||||||
file, err := os.Create(destination)
|
file, err := os.Create(destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
writer := zip.NewWriter(file)
|
writer := zip.NewWriter(file)
|
||||||
|
|
@ -486,22 +398,22 @@ func ZipDirectory(destination string, source string) (err error) {
|
||||||
defer writer.Close()
|
defer writer.Close()
|
||||||
err = filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
|
err = filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
if info.Mode().IsRegular() {
|
if info.Mode().IsRegular() {
|
||||||
f1, err := os.Open(path)
|
f1, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
defer f1.Close()
|
defer f1.Close()
|
||||||
zipPath := strings.ReplaceAll(path, source, strings.TrimSuffix(destination, ".zip"))
|
zipPath := strings.ReplaceAll(path, source, strings.TrimSuffix(destination, ".zip"))
|
||||||
zipPath = filepath.ToSlash(zipPath)
|
zipPath = filepath.ToSlash(zipPath)
|
||||||
w1, err := writer.Create(zipPath)
|
w1, err := writer.Create(zipPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(w1, f1); err != nil {
|
if _, err := io.Copy(w1, f1); err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "\r\033[2K")
|
fmt.Fprintf(os.Stderr, "\r\033[2K")
|
||||||
fmt.Fprintf(os.Stderr, "\rAdding %s", zipPath)
|
fmt.Fprintf(os.Stderr, "\rAdding %s", zipPath)
|
||||||
|
|
@ -509,7 +421,7 @@ func ZipDirectory(destination string, source string) (err error) {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(os.Stderr, "\n")
|
fmt.Fprintf(os.Stderr, "\n")
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -518,7 +430,7 @@ func ZipDirectory(destination string, source string) (err error) {
|
||||||
func UnzipDirectory(destination string, source string) error {
|
func UnzipDirectory(destination string, source string) error {
|
||||||
archive, err := zip.OpenReader(source)
|
archive, err := zip.OpenReader(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
defer archive.Close()
|
defer archive.Close()
|
||||||
|
|
||||||
|
|
@ -526,43 +438,27 @@ func UnzipDirectory(destination string, source string) error {
|
||||||
filePath := filepath.Join(destination, f.Name)
|
filePath := filepath.Join(destination, f.Name)
|
||||||
fmt.Fprintf(os.Stderr, "\r\033[2K")
|
fmt.Fprintf(os.Stderr, "\r\033[2K")
|
||||||
fmt.Fprintf(os.Stderr, "\rUnzipping file %s", filePath)
|
fmt.Fprintf(os.Stderr, "\rUnzipping file %s", filePath)
|
||||||
// Issue #593 conceal path traversal vulnerability
|
|
||||||
// make sure the filepath does not have ".."
|
|
||||||
filePath = filepath.Clean(filePath)
|
|
||||||
if strings.Contains(filePath, "..") {
|
|
||||||
log.Errorf("Invalid file path %s\n", filePath)
|
|
||||||
}
|
|
||||||
if f.FileInfo().IsDir() {
|
if f.FileInfo().IsDir() {
|
||||||
os.MkdirAll(filePath, os.ModePerm)
|
os.MkdirAll(filePath, os.ModePerm)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
|
||||||
|
|
||||||
// check if file exists
|
|
||||||
if _, err := os.Stat(filePath); err == nil {
|
|
||||||
prompt := fmt.Sprintf("\nOverwrite '%s'? (y/N) ", filePath)
|
|
||||||
choice := strings.ToLower(GetInput(prompt))
|
|
||||||
if choice != "y" && choice != "yes" {
|
|
||||||
fmt.Fprintf(os.Stderr, "Skipping '%s'\n", filePath)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileInArchive, err := f.Open()
|
fileInArchive, err := f.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
|
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
|
||||||
log.Error(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dstFile.Close()
|
dstFile.Close()
|
||||||
|
|
@ -571,67 +467,3 @@ func UnzipDirectory(destination string, source string) error {
|
||||||
fmt.Fprintf(os.Stderr, "\n")
|
fmt.Fprintf(os.Stderr, "\n")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidFileName checks if a filename is valid
|
|
||||||
// by making sure it has no invisible characters
|
|
||||||
func ValidFileName(fname string) (err error) {
|
|
||||||
// make sure it doesn't contain unicode or invisible characters
|
|
||||||
for _, r := range fname {
|
|
||||||
if !unicode.IsGraphic(r) {
|
|
||||||
err = fmt.Errorf("non-graphical unicode: %x U+%d in '%x'", string(r), r, fname)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !unicode.IsPrint(r) {
|
|
||||||
err = fmt.Errorf("non-printable unicode: %x U+%d in '%x'", string(r), r, fname)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// make sure basename does not include ".." or path separators
|
|
||||||
_, basename := filepath.Split(fname)
|
|
||||||
if strings.Contains(basename, "..") {
|
|
||||||
err = fmt.Errorf("basename cannot contain '..': '%s'", basename)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.Contains(basename, string(os.PathSeparator)) {
|
|
||||||
err = fmt.Errorf("basename cannot contain path separators: '%s'", basename)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// make sure the filename is not an absolute path
|
|
||||||
if filepath.IsAbs(fname) {
|
|
||||||
err = fmt.Errorf("filename cannot be an absolute path: '%s'", fname)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const crocRemovalFile = "croc-marked-files.txt"
|
|
||||||
|
|
||||||
func MarkFileForRemoval(fname string) {
|
|
||||||
// append the fname to the list of files to remove
|
|
||||||
f, err := os.OpenFile(crocRemovalFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o600)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
_, err = f.WriteString(fname + "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemoveMarkedFiles() (err error) {
|
|
||||||
// read the file and remove all the files
|
|
||||||
f, err := os.Open(crocRemovalFile)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
scanner := bufio.NewScanner(f)
|
|
||||||
for scanner.Scan() {
|
|
||||||
fname := scanner.Text()
|
|
||||||
err = os.Remove(fname)
|
|
||||||
if err == nil {
|
|
||||||
log.Tracef("Removed %s", fname)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
os.Remove(crocRemovalFile)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -25,7 +24,7 @@ func BenchmarkMD5(b *testing.B) {
|
||||||
bigFile()
|
bigFile()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
MD5HashFile("bigfile.test", false)
|
MD5HashFile("bigfile.test")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,7 +32,7 @@ func BenchmarkXXHash(b *testing.B) {
|
||||||
bigFile()
|
bigFile()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
XXHashFile("bigfile.test", false)
|
XXHashFile("bigfile.test")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,14 +44,6 @@ func BenchmarkImoHash(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkHighwayHash(b *testing.B) {
|
|
||||||
bigFile()
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
HighwayHashFile("bigfile.test", false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkImoHashFull(b *testing.B) {
|
func BenchmarkImoHashFull(b *testing.B) {
|
||||||
bigFile()
|
bigFile()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
@ -87,20 +78,10 @@ func TestExists(t *testing.T) {
|
||||||
func TestMD5HashFile(t *testing.T) {
|
func TestMD5HashFile(t *testing.T) {
|
||||||
bigFile()
|
bigFile()
|
||||||
defer os.Remove("bigfile.test")
|
defer os.Remove("bigfile.test")
|
||||||
b, err := MD5HashFile("bigfile.test", false)
|
b, err := MD5HashFile("bigfile.test")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "8304ff018e02baad0e3555bade29a405", fmt.Sprintf("%x", b))
|
assert.Equal(t, "8304ff018e02baad0e3555bade29a405", fmt.Sprintf("%x", b))
|
||||||
_, err = MD5HashFile("bigfile.test.nofile", false)
|
_, err = MD5HashFile("bigfile.test.nofile")
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHighwayHashFile(t *testing.T) {
|
|
||||||
bigFile()
|
|
||||||
defer os.Remove("bigfile.test")
|
|
||||||
b, err := HighwayHashFile("bigfile.test", false)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
assert.Equal(t, "3c32999529323ed66a67aeac5720c7bf1301dcc5dca87d8d46595e85ff990329", fmt.Sprintf("%x", b))
|
|
||||||
_, err = HighwayHashFile("bigfile.test.nofile", false)
|
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,16 +90,16 @@ func TestIMOHashFile(t *testing.T) {
|
||||||
defer os.Remove("bigfile.test")
|
defer os.Remove("bigfile.test")
|
||||||
b, err := IMOHashFile("bigfile.test")
|
b, err := IMOHashFile("bigfile.test")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "c0d1e12301e6c635f6d4a8ea5c897437", fmt.Sprintf("%x", b))
|
assert.Equal(t, "c0d1e123ca94148ffea146137684ebb9", fmt.Sprintf("%x", b))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestXXHashFile(t *testing.T) {
|
func TestXXHashFile(t *testing.T) {
|
||||||
bigFile()
|
bigFile()
|
||||||
defer os.Remove("bigfile.test")
|
defer os.Remove("bigfile.test")
|
||||||
b, err := XXHashFile("bigfile.test", false)
|
b, err := XXHashFile("bigfile.test")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "4918740eb5ccb6f7", fmt.Sprintf("%x", b))
|
assert.Equal(t, "4918740eb5ccb6f7", fmt.Sprintf("%x", b))
|
||||||
_, err = XXHashFile("nofile", false)
|
_, err = XXHashFile("nofile")
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,41 +208,11 @@ func TestGetRandomName(t *testing.T) {
|
||||||
assert.NotEmpty(t, name)
|
assert.NotEmpty(t, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func intSliceSame(a, b []int) bool {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i, v := range a {
|
|
||||||
if v != b[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFindOpenPorts(t *testing.T) {
|
func TestFindOpenPorts(t *testing.T) {
|
||||||
openPorts := FindOpenPorts("127.0.0.1", 9009, 4)
|
openPorts := FindOpenPorts("127.0.0.1", 9009, 4)
|
||||||
if !intSliceSame(openPorts, []int{9009, 9010, 9011, 9012}) && !intSliceSame(openPorts, []int{9014, 9015, 9016, 9017}) {
|
assert.Equal(t, []int{9009, 9010, 9011, 9012}, openPorts)
|
||||||
t.Errorf("openPorts: %v", openPorts)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsLocalIP(t *testing.T) {
|
func TestIsLocalIP(t *testing.T) {
|
||||||
assert.True(t, IsLocalIP("192.168.0.14:9009"))
|
assert.True(t, IsLocalIP("192.168.0.14:9009"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidFileName(t *testing.T) {
|
|
||||||
// contains regular characters
|
|
||||||
assert.Nil(t, ValidFileName("中文.csl"))
|
|
||||||
// contains regular characters
|
|
||||||
assert.Nil(t, ValidFileName("[something].csl"))
|
|
||||||
// contains regular characters
|
|
||||||
assert.Nil(t, ValidFileName("[(something)].csl"))
|
|
||||||
// contains invisible character
|
|
||||||
err := ValidFileName("D中文.cslouglas")
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
assert.Equal(t, "non-graphical unicode: e2808b U+8203 in '44e4b8ade696872e63736c6f75676c6173e2808b'", err.Error())
|
|
||||||
assert.NotNil(t, ValidFileName("hi..txt"))
|
|
||||||
assert.NotNil(t, ValidFileName(path.Join(string(os.PathSeparator), "abs", string(os.PathSeparator), "hi.txt")))
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue