Compare commits
No commits in common. "main" and "v9.6.0" have entirely different histories.
|
|
@ -1,9 +1,41 @@
|
|||
---
|
||||
name: New issue
|
||||
about: Create an issue
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
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.
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
|
@ -1,52 +1,18 @@
|
|||
name: CI
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
unit-tests:
|
||||
name: Go unit tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.18'
|
||||
- run: go version
|
||||
- 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
|
||||
|
|
|
|||
|
|
@ -4,15 +4,10 @@ name: CD
|
|||
|
||||
# Controls when the action will run.
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the main branch
|
||||
# Triggers the workflow on push or pull request events but only for the master branch
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
tags:
|
||||
- 'v*'
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
|
@ -24,37 +19,32 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Docker meta
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: crazy-max/ghaction-docker-meta@v1
|
||||
with:
|
||||
images: schollz/croc
|
||||
# generate Docker tags based on the following events/attributes
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha
|
||||
# tag-semver: "{{version}}"
|
||||
tag-sha: true
|
||||
tag-latest: true
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@v1
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v1
|
||||
-
|
||||
name: Login to DockerHub
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
-
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
|
|
|
|||
|
|
@ -1,131 +0,0 @@
|
|||
name: Make release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [created]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout project
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.23'
|
||||
- name: Prepare source tarball
|
||||
run: |
|
||||
git clone -b ${{ github.event.release.name }} --depth 1 https://github.com/schollz/croc croc-${{ github.event.release.name }}
|
||||
cd croc-${{ github.event.release.name }} && go mod tidy && go mod vendor
|
||||
cd .. && tar -czvf croc_${{ github.event.release.name }}_src.tar.gz croc-${{ github.event.release.name }}
|
||||
- name: Build files
|
||||
run: |
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags '-extldflags "-static"' -o croc.exe
|
||||
zip croc_${{ github.event.release.name }}_Windows-64bit.zip croc.exe LICENSE
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags '-extldflags "-static"' -o croc.exe
|
||||
zip croc_${{ github.event.release.name }}_Windows-32bit.zip croc.exe LICENSE
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=arm go build -ldflags '-extldflags "-static"' -o croc.exe
|
||||
zip croc_${{ github.event.release.name }}_Windows-ARM.zip croc.exe LICENSE
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=arm64 go build -ldflags '-extldflags "-static"' -o croc.exe
|
||||
zip croc_${{ github.event.release.name }}_Windows-ARM64.zip croc.exe LICENSE
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags '-extldflags "-static"' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_Linux-64bit.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags '-extldflags "-static"' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_Linux-32bit.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags '-extldflags "-static"' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_Linux-ARM.tar.gz croc LICENSE
|
||||
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
|
||||
tar -czvf croc_${{ github.event.release.name }}_Linux-ARM64.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags '-s -extldflags "-sectcreate __TEXT __info_plist Info.plist"' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_macOS-64bit.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -ldflags '-s -extldflags "-sectcreate __TEXT __info_plist Info.plist"' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_macOS-ARM64.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=dragonfly GOARCH=amd64 go build -ldflags '' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_DragonFlyBSD-64bit.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags '' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_FreeBSD-64bit.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=freebsd GOARCH=arm64 go build -ldflags '' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_FreeBSD-ARM64.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=netbsd GOARCH=386 go build -ldflags '' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_NetBSD-32bit.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=netbsd GOARCH=amd64 go build -ldflags '' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_NetBSD-64bit.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=netbsd GOARCH=arm64 go build -ldflags '' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_NetBSD-ARM64.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=openbsd GOARCH=amd64 go build -ldflags '' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_OpenBSD-64bit.tar.gz croc LICENSE
|
||||
CGO_ENABLED=0 GOOS=openbsd GOARCH=arm64 go build -ldflags '' -o croc
|
||||
tar -czvf croc_${{ github.event.release.name }}_OpenBSD-ARM64.tar.gz croc LICENSE
|
||||
- name: 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
|
||||
run: |
|
||||
touch croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_src.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Windows-64bit.zip >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Windows-32bit.zip >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Windows-ARM.zip >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Windows-ARM64.zip >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Windows7-64bit.zip >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Windows7-32bit.zip >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Linux-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Linux-32bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Linux-ARM.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_Linux-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 }}_macOS-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_macOS-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_DragonFlyBSD-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_FreeBSD-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_FreeBSD-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_NetBSD-32bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_NetBSD-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_NetBSD-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_OpenBSD-64bit.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
sha256sum croc_${{ github.event.release.name }}_OpenBSD-ARM64.tar.gz >> croc_${{ github.event.release.name }}_checksums.txt
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
croc_${{ github.event.release.name }}_checksums.txt
|
||||
croc_${{ github.event.release.name }}_src.tar.gz
|
||||
croc_${{ github.event.release.name }}_Windows-64bit.zip
|
||||
croc_${{ github.event.release.name }}_Windows-32bit.zip
|
||||
croc_${{ github.event.release.name }}_Windows-ARM.zip
|
||||
croc_${{ github.event.release.name }}_Windows-ARM64.zip
|
||||
croc_${{ github.event.release.name }}_Windows7-64bit.zip
|
||||
croc_${{ github.event.release.name }}_Windows7-32bit.zip
|
||||
croc_${{ github.event.release.name }}_Linux-64bit.tar.gz
|
||||
croc_${{ github.event.release.name }}_Linux-32bit.tar.gz
|
||||
croc_${{ github.event.release.name }}_Linux-ARM.tar.gz
|
||||
croc_${{ github.event.release.name }}_Linux-ARMv5.tar.gz
|
||||
croc_${{ github.event.release.name }}_Linux-ARM64.tar.gz
|
||||
croc_${{ github.event.release.name }}_macOS-64bit.tar.gz
|
||||
croc_${{ github.event.release.name }}_macOS-ARM64.tar.gz
|
||||
croc_${{ github.event.release.name }}_DragonFlyBSD-64bit.tar.gz
|
||||
croc_${{ github.event.release.name }}_FreeBSD-64bit.tar.gz
|
||||
croc_${{ github.event.release.name }}_FreeBSD-ARM64.tar.gz
|
||||
croc_${{ github.event.release.name }}_NetBSD-32bit.tar.gz
|
||||
croc_${{ github.event.release.name }}_NetBSD-64bit.tar.gz
|
||||
croc_${{ github.event.release.name }}_NetBSD-ARM64.tar.gz
|
||||
croc_${{ github.event.release.name }}_OpenBSD-64bit.tar.gz
|
||||
croc_${{ github.event.release.name }}_OpenBSD-ARM64.tar.gz
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
|
||||
#
|
||||
# You can adjust the behavior by modifying this file.
|
||||
# For more information, see:
|
||||
# https://github.com/actions/stale
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '19 12 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'Stale issue message'
|
||||
stale-pr-message: 'Stale pull request message'
|
||||
stale-issue-label: 'no-issue-activity'
|
||||
stale-pr-label: 'no-pr-activity'
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
name: Publish to Winget
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: vedantmgoyal2009/winget-releaser@v2
|
||||
with:
|
||||
identifier: schollz.croc
|
||||
installers-regex: '_Windows-\w+\.zip$'
|
||||
token: ${{ secrets.WINGET_TOKEN }}
|
||||
|
|
@ -9,5 +9,3 @@ croc-stdin*
|
|||
|
||||
.idea/
|
||||
.vscode/
|
||||
src/utils/bigfile.test
|
||||
test1/
|
||||
|
|
|
|||
|
|
@ -97,4 +97,4 @@ announce:
|
|||
twitter:
|
||||
# Wether its enabled or not.
|
||||
# Defaults to false.
|
||||
enabled: false
|
||||
enabled: true
|
||||
|
|
|
|||
12
.travis.yml
12
.travis.yml
|
|
@ -10,12 +10,12 @@ install: true
|
|||
|
||||
script:
|
||||
- env GO111MODULE=on go build -v
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/compress
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/croc
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/crypt
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/tcp
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/utils
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v10/src/comm
|
||||
- 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/v9/src/croc
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/crypt
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/tcp
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/utils
|
||||
- env GO111MODULE=on go test -v -cover github.com/schollz/croc/v9/src/comm
|
||||
|
||||
branches:
|
||||
except:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
FROM golang:1.22-alpine as builder
|
||||
RUN apk add --no-cache git gcc musl-dev
|
||||
FROM golang:1.17-alpine as builder
|
||||
RUN apk add --no-cache git
|
||||
WORKDIR /go/croc
|
||||
COPY . .
|
||||
RUN go build -v -ldflags="-s -w"
|
||||
|
|
|
|||
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017-2024 Zack
|
||||
Copyright (c) 2017-2021 Zack
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
56
README.md
56
README.md
|
|
@ -4,9 +4,10 @@
|
|||
src="https://user-images.githubusercontent.com/6550035/46709024-9b23ad00-cbf6-11e8-9fb2-ca8b20b7dbec.jpg"
|
||||
width="408px" border="0" alt="croc">
|
||||
<br>
|
||||
<a href="https://github.com/schollz/croc/releases/latest"><img src="https://img.shields.io/badge/version-v10.1.1-brightgreen.svg?style=flat-square" alt="Version"></a>
|
||||
<a href="https://github.com/schollz/croc/actions/workflows/ci.yml"><img
|
||||
src="https://github.com/schollz/croc/actions/workflows/ci.yml/badge.svg" alt="Build
|
||||
<a href="https://github.com/schollz/croc/releases/latest"><img src="https://img.shields.io/badge/version-v9.6.0-brightgreen.svg?style=flat-square" alt="Version"></a>
|
||||
<a href="https://coveralls.io/github/schollz/croc"><img src="https://img.shields.io/badge/coverage-81%25-green.svg?style=flat-square" alt="Coverage"></a>
|
||||
<a href="https://travis-ci.org/schollz/croc"><img
|
||||
src="https://img.shields.io/travis/schollz/croc.svg?style=flat-square" alt="Build
|
||||
Status"></a>
|
||||
<p align="center">This project is supported by <a href="https://github.com/sponsors/schollz">Github sponsors</a>.</p>
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ sudo port selfupdate
|
|||
sudo port install croc
|
||||
```
|
||||
|
||||
On Windows you can install the latest release with [Scoop](https://scoop.sh/), [Chocolatey](https://chocolatey.org), or [Winget](https://learn.microsoft.com/en-us/windows/package-manager/):
|
||||
On Windows you can install the latest release with [Scoop](https://scoop.sh/) or [Chocolatey](https://chocolatey.org):
|
||||
|
||||
```
|
||||
scoop install croc
|
||||
|
|
@ -57,10 +58,6 @@ scoop install croc
|
|||
choco install croc
|
||||
```
|
||||
|
||||
```
|
||||
winget install schollz.croc
|
||||
```
|
||||
|
||||
On Unix you can install the latest release with [Nix](https://nixos.org/nix):
|
||||
|
||||
```
|
||||
|
|
@ -104,28 +101,16 @@ On FreeBSD you can install with `pkg`:
|
|||
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/):
|
||||
Or, you can [install Go](https://golang.org/dl/) and build from source (requires Go 1.17+):
|
||||
|
||||
```
|
||||
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+):
|
||||
|
||||
```
|
||||
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/).
|
||||
|
||||
|
||||
## Usage
|
||||
## Usage
|
||||
|
||||
To send a file, simply do:
|
||||
|
||||
|
|
@ -145,25 +130,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`.
|
||||
|
||||
### 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
|
||||
|
||||
You can send with your own code phrase (must be more than 6 characters).
|
||||
|
|
@ -198,7 +164,7 @@ croc --yes [code-phrase] > out
|
|||
All of the other text printed to the console is going to `stderr` so it will not interfere with the message going to `stdout`.
|
||||
|
||||
|
||||
### Send text
|
||||
### Send text
|
||||
|
||||
Sometimes you want to send URLs or short text. In addition to piping, you can easily send text with `croc`:
|
||||
|
||||
|
|
@ -243,7 +209,7 @@ The relay is needed to staple the parallel incoming and outgoing connections. By
|
|||
croc relay
|
||||
```
|
||||
|
||||
By default it uses TCP ports 9009-9013. Make sure to open those up. You can customize the ports (e.g. `croc relay --ports 1111,1112`), but you must have a minimum of **2** ports for the relay. The first port is for communication and the subsequent ports are used for the multiplexed data transfer.
|
||||
By default it uses TCP ports 9009-9013. Make sure to open those up. You can customized the ports (e.g. `croc relay --ports 1111,1112`), but you must have a minimum of **2** ports for the relay. The first port is for communication and the subsequent ports are used for the multiplexed data transfer.
|
||||
|
||||
You can send files using your relay by entering `--relay` to change the relay that you are using if you want to custom host your own.
|
||||
|
||||
|
|
@ -276,6 +242,6 @@ MIT
|
|||
|
||||
## Acknowledgements
|
||||
|
||||
`croc` has gone through many iterations, and I am awed by all the great contributions! If you feel like contributing, in any way, by all means you can send an Issue, a PR, or ask a question.
|
||||
`croc` has gone through many iterations, and I am awed by all the great contributions! If you feel like contributing, in any way, by all means you can send an Issue, a PR, ask a question, or tweet me ([@yakczar](http://ctt.ec/Rq054)).
|
||||
|
||||
Thanks [@warner](https://github.com/warner) for the [idea](https://github.com/warner/magic-wormhole), [@tscholl2](https://github.com/tscholl2) for the [encryption gists](https://gist.github.com/tscholl2/dc7dc15dc132ea70a98e8542fefffa28), [@skorokithakis](https://github.com/skorokithakis) for [code on proxying two connections](https://www.stavros.io/posts/proxying-two-connections-go/). Finally thanks for making pull requests [@maximbaz](https://github.com/maximbaz), [@meyermarcel](https://github.com/meyermarcel), [@Girbons](https://github.com/Girbons), [@techtide](https://github.com/techtide), [@heymatthew](https://github.com/heymatthew), [@Lunsford94](https://github.com/Lunsford94), [@lummie](https://github.com/lummie), [@jesuiscamille](https://github.com/jesuiscamille), [@threefjord](https://github.com/threefjord), [@marcossegovia](https://github.com/marcossegovia), [@csleong98](https://github.com/csleong98), [@afotescu](https://github.com/afotescu), [@callmefever](https://github.com/callmefever), [@El-JojA](https://github.com/El-JojA), [@anatolyyyyyy](https://github.com/anatolyyyyyy), [@goggle](https://github.com/goggle), [@smileboywtu](https://github.com/smileboywtu), [@nicolashardy](https://github.com/nicolashardy), [@fbartels](https://github.com/fbartels), [@rkuprov](https://github.com/rkuprov), [@hreese](https://github.com/hreese), [@xenrox](https://github.com/xenrox) and [Ipar](https://github.com/lpar)!
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ After=network.target
|
|||
|
||||
[Service]
|
||||
Type=simple
|
||||
DynamicUser=yes
|
||||
User=nobody
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
ExecStart=/usr/bin/croc relay
|
||||
|
||||
|
|
|
|||
48
go.mod
48
go.mod
|
|
@ -1,39 +1,39 @@
|
|||
module github.com/schollz/croc/v10
|
||||
module github.com/schollz/croc/v9
|
||||
|
||||
go 1.22
|
||||
|
||||
toolchain go1.23.1
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/chzyer/readline v1.5.1
|
||||
github.com/denisbrodbeck/machineid v1.0.1
|
||||
github.com/kalafut/imohash v1.1.0
|
||||
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/kalafut/imohash v1.0.2
|
||||
github.com/schollz/cli/v2 v2.2.1
|
||||
github.com/schollz/logger v1.2.0
|
||||
github.com/schollz/pake/v3 v3.0.5
|
||||
github.com/schollz/peerdiscovery v1.7.5
|
||||
github.com/schollz/progressbar/v3 v3.17.1
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/crypto v0.29.0
|
||||
golang.org/x/net v0.31.0
|
||||
golang.org/x/sys v0.27.0
|
||||
golang.org/x/term v0.26.0
|
||||
golang.org/x/time v0.8.0
|
||||
github.com/schollz/mnemonicode v1.0.1
|
||||
github.com/schollz/pake/v3 v3.0.4
|
||||
github.com/schollz/peerdiscovery v1.6.12
|
||||
github.com/schollz/progressbar/v3 v3.8.6
|
||||
github.com/stretchr/testify v1.6.1
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.5 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406 // indirect
|
||||
github.com/twmb/murmur3 v1.1.8 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/tscholl2/siec v0.0.0-20210707234609-9bdfc483d499 // indirect
|
||||
github.com/twmb/murmur3 v1.1.6 // indirect
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e // indirect
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
)
|
||||
|
|
|
|||
178
go.sum
178
go.sum
|
|
@ -1,148 +1,106 @@
|
|||
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.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI=
|
||||
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/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/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
|
||||
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/kalafut/imohash v1.1.0 h1:Lldcmx0SXgMSoABB2WBD8mTgf0OlVnISn2Dyrfg2Ep8=
|
||||
github.com/kalafut/imohash v1.1.0/go.mod h1:6cn9lU0Sj8M4eu9UaQm1kR/5y3k/ayB68yntRhGloL4=
|
||||
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI=
|
||||
github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
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/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/kalafut/imohash v1.0.2 h1:j/cUPa15YvXv7abJlM+kdJIycbBMpmO7WqhPl4YB76I=
|
||||
github.com/kalafut/imohash v1.0.2/go.mod h1:PjHBF0vpo1q7zMqiTn0qwSTQU2wDn5QIe8S8sFQuZS8=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
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/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
|
||||
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
|
||||
github.com/schollz/cli/v2 v2.2.1 h1:ou22Mj7ZPjrKz+8k2iDTWaHskEEV5NiAxGrdsCL36VU=
|
||||
github.com/schollz/cli/v2 v2.2.1/go.mod h1:My6bfphRLZUhZdlFUK8scAxMWHydE7k4s2ed2Dtnn+s=
|
||||
github.com/schollz/logger v1.2.0 h1:5WXfINRs3lEUTCZ7YXhj0uN+qukjizvITLm3Ca2m0Ho=
|
||||
github.com/schollz/logger v1.2.0/go.mod h1:P6F4/dGMGcx8wh+kG1zrNEd4vnNpEBY/mwEMd/vn6AM=
|
||||
github.com/schollz/pake/v3 v3.0.5 h1:MnZVdI987lkjln9BSx/zUb724TZISa2jbO+dPj6BvgQ=
|
||||
github.com/schollz/pake/v3 v3.0.5/go.mod h1:OGbG6htRwSKo6V8R5tg61ufpFmZM1b/PrrSp6g2ZLLc=
|
||||
github.com/schollz/peerdiscovery v1.7.5 h1:0cEhO+o8i4fpeKBwl7u0UY3Kt3XVt5fSzS4rg17ZPb4=
|
||||
github.com/schollz/peerdiscovery v1.7.5/go.mod h1:Crht2FOfD1/eL3U/AIM0vvwVZDPePlBgSX3Xw+TnJoE=
|
||||
github.com/schollz/progressbar/v3 v3.17.1 h1:bI1MTaoQO+v5kzklBjYNRQLoVpe0zbyRZNK6DFkVC5U=
|
||||
github.com/schollz/progressbar/v3 v3.17.1/go.mod h1:RzqpnsPQNjUyIgdglUjRLgD7sVnxN1wpmBMV+UiEbL4=
|
||||
github.com/schollz/mnemonicode v1.0.1 h1:LiH5hwADZwjwnfXsaD4xgnMyTAtaKHN+e5AyjRU6WSU=
|
||||
github.com/schollz/mnemonicode v1.0.1/go.mod h1:cl4UAOhUV0mkdjMj/QYaUZbZZdF8BnOqoz8rHMzwboY=
|
||||
github.com/schollz/pake/v3 v3.0.4 h1:rDNk9MwEVJ/C1+eDCr0DirJfpG+/sAZJ4YsYIyOTkSc=
|
||||
github.com/schollz/pake/v3 v3.0.4/go.mod h1:Q28rSQCHYzEtMQoi80R1MdpPRgNN/Si2Xdilx4NvsoQ=
|
||||
github.com/schollz/peerdiscovery v1.6.11 h1:3SG5vV1plIxylDg81fKgnqyrvlem5MrNcgcb0TLBjlE=
|
||||
github.com/schollz/peerdiscovery v1.6.11/go.mod h1:duO2S6wH3IuPJXwniPXp/9f69S2gFUSA9ePbAcKatJg=
|
||||
github.com/schollz/peerdiscovery v1.6.12 h1:8N/MEjMSPIwQRjEiyHC1B3goax4INvuRo3exuwICwik=
|
||||
github.com/schollz/peerdiscovery v1.6.12/go.mod h1:fYHOyZQetvFkK+iQbLH/Gll28Fh9WJywIN550GkVMR4=
|
||||
github.com/schollz/progressbar/v3 v3.8.6 h1:QruMUdzZ1TbEP++S1m73OqRJk20ON11m6Wqv4EoGg8c=
|
||||
github.com/schollz/progressbar/v3 v3.8.6/go.mod h1:W5IEwbJecncFGBvuEh4A7HT1nZZ6WNIL2i3qbnI0WKY=
|
||||
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 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tscholl2/siec v0.0.0-20210707234609-9bdfc483d499 h1:bPQ48TuiAuGTZDm54H2EV/2+eRRBHP61bKDkKSEPW4A=
|
||||
github.com/tscholl2/siec v0.0.0-20210707234609-9bdfc483d499/go.mod h1:KL9+ubr1JZdaKjgAaHr+tCytEncXBa1pR6FjbTsOJnw=
|
||||
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406 h1:sDWDZkwYqX0jvLWstKzFwh+pYhQNaVg65BgSkCP/f7U=
|
||||
github.com/tscholl2/siec v0.0.0-20240310163802-c2c6f6198406/go.mod h1:KL9+ubr1JZdaKjgAaHr+tCytEncXBa1pR6FjbTsOJnw=
|
||||
github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||
github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg=
|
||||
github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.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.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.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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
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-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.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=
|
||||
github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg=
|
||||
github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ=
|
||||
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898 h1:SLP7Q4Di66FONjDJbCYrCRrh97focO6sLogHO7/g8F0=
|
||||
golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220517181318-183a9ca12b87 h1:cCR+9mKLOGyX4Zx+uBZDXEDAQsvKQ/XbW4vreG5v1jU=
|
||||
golang.org/x/net v0.0.0-20220517181318-183a9ca12b87/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60 h1:8NSylCMxLW4JvserAndSgFL7aPli6A68yf0bYFTcWCM=
|
||||
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e h1:w36l2Uw3dRan1K3TyXriXvY+6T56GNmlKGcqiQUJDfM=
|
||||
golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.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.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/sys v0.0.0-20220704084225-05e143d24a9e h1:CsOuNlbOuf0mzxJIefr6Q4uAUetRUwZE4qt7VfzP+xo=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
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/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8=
|
||||
golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.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.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
|
||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/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=
|
||||
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 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/tylerb/is.v1 v1.1.2 h1:AB/MANFml2ySf+adwcinvajyHvsYltAOD+rb/8njfSU=
|
||||
gopkg.in/tylerb/is.v1 v1.1.2/go.mod h1:9yQB2tyIhZ5oph6Kk5Sq7cJMd9c5Jpa1p3hr9kxzPqo=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
32
main.go
32
main.go
|
|
@ -5,13 +5,9 @@ package main
|
|||
//go:generate git tag -af v$VERSION -m "v$VERSION"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"log"
|
||||
|
||||
"github.com/schollz/croc/v10/src/cli"
|
||||
"github.com/schollz/croc/v10/src/utils"
|
||||
"github.com/schollz/croc/v9/src/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
@ -31,25 +27,7 @@ func main() {
|
|||
// fmt.Println("wrote profile")
|
||||
// }
|
||||
// }()
|
||||
|
||||
// Create a channel to receive OS signals
|
||||
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)
|
||||
if err := cli.Run(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
356
src/cli/cli.go
356
src/cli/cli.go
|
|
@ -9,18 +9,15 @@ import (
|
|||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/chzyer/readline"
|
||||
"github.com/schollz/cli/v2"
|
||||
"github.com/schollz/croc/v10/src/comm"
|
||||
"github.com/schollz/croc/v10/src/croc"
|
||||
"github.com/schollz/croc/v10/src/mnemonicode"
|
||||
"github.com/schollz/croc/v10/src/models"
|
||||
"github.com/schollz/croc/v10/src/tcp"
|
||||
"github.com/schollz/croc/v10/src/utils"
|
||||
"github.com/schollz/croc/v9/src/comm"
|
||||
"github.com/schollz/croc/v9/src/croc"
|
||||
"github.com/schollz/croc/v9/src/models"
|
||||
"github.com/schollz/croc/v9/src/tcp"
|
||||
"github.com/schollz/croc/v9/src/utils"
|
||||
log "github.com/schollz/logger"
|
||||
"github.com/schollz/pake/v3"
|
||||
)
|
||||
|
|
@ -36,18 +33,14 @@ func Run() (err error) {
|
|||
app := cli.NewApp()
|
||||
app.Name = "croc"
|
||||
if Version == "" {
|
||||
Version = "v10.1.0"
|
||||
Version = "v9.6.0-0e93f1e"
|
||||
}
|
||||
app.Version = Version
|
||||
app.Compiled = time.Now()
|
||||
app.Usage = "easily and securely transfer stuff from one computer to another"
|
||||
app.UsageText = `croc [GLOBAL OPTIONS] [COMMAND] [COMMAND OPTIONS] [filename(s) or folder]
|
||||
|
||||
USAGE EXAMPLES:
|
||||
Send a file:
|
||||
app.UsageText = `Send a file:
|
||||
croc send file.txt
|
||||
|
||||
-git to respect your .gitignore
|
||||
Send multiple files:
|
||||
croc send file1.txt file2.txt file3.txt
|
||||
or
|
||||
|
|
@ -74,10 +67,7 @@ func Run() (err error) {
|
|||
&cli.StringFlag{Name: "text", Aliases: []string{"t"}, Usage: "send some text"},
|
||||
&cli.BoolFlag{Name: "no-local", Usage: "disable local relay when sending"},
|
||||
&cli.BoolFlag{Name: "no-multi", Usage: "disable multiplexing"},
|
||||
&cli.BoolFlag{Name: "git", Usage: "enable .gitignore respect / don't send ignored files"},
|
||||
&cli.IntFlag{Name: "port", Value: 9009, Usage: "base port for the relay"},
|
||||
&cli.IntFlag{Name: "transfers", Value: 4, Usage: "number of ports to use for transfers"},
|
||||
&cli.BoolFlag{Name: "qrcode", Aliases: []string{"qr"}, Usage: "show receive code as a qrcode"},
|
||||
&cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the local relay (optional)"},
|
||||
},
|
||||
HelpName: "croc send",
|
||||
Action: send,
|
||||
|
|
@ -91,14 +81,11 @@ func Run() (err error) {
|
|||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{Name: "host", Usage: "host of the relay"},
|
||||
&cli.StringFlag{Name: "ports", Value: "9009,9010,9011,9012,9013", Usage: "ports of the relay"},
|
||||
&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{
|
||||
&cli.BoolFlag{Name: "internal-dns", Usage: "use a built-in DNS stub resolver rather than the host operating system"},
|
||||
&cli.BoolFlag{Name: "classic", Usage: "toggle between the classic mode (insecure due to local attack vector) and new mode (secure)"},
|
||||
&cli.BoolFlag{Name: "remember", Usage: "save these settings to reuse next time"},
|
||||
&cli.BoolFlag{Name: "debug", Usage: "toggle debug mode"},
|
||||
&cli.BoolFlag{Name: "yes", Usage: "automatically agree to all prompts"},
|
||||
|
|
@ -107,9 +94,7 @@ func Run() (err error) {
|
|||
&cli.BoolFlag{Name: "ask", Usage: "make sure sender and recipient are prompted"},
|
||||
&cli.BoolFlag{Name: "local", Usage: "force to use only local connections"},
|
||||
&cli.BoolFlag{Name: "ignore-stdin", Usage: "ignore piped stdin"},
|
||||
&cli.BoolFlag{Name: "overwrite", Usage: "do not prompt to overwrite or resume"},
|
||||
&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.BoolFlag{Name: "overwrite", Usage: "do not prompt to overwrite"},
|
||||
&cli.StringFlag{Name: "curve", Value: "p256", Usage: "choose an encryption curve (" + strings.Join(pake.AvailableCurves(), ", ") + ")"},
|
||||
&cli.StringFlag{Name: "ip", Value: "", Usage: "set sender ip if known e.g. 10.0.0.1:9009, [::1]:9009"},
|
||||
&cli.StringFlag{Name: "relay", Value: models.DEFAULT_RELAY, Usage: "address of the relay", EnvVars: []string{"CROC_RELAY"}},
|
||||
|
|
@ -117,7 +102,6 @@ func Run() (err error) {
|
|||
&cli.StringFlag{Name: "out", Value: ".", Usage: "specify an output folder to receive the file"},
|
||||
&cli.StringFlag{Name: "pass", Value: models.DEFAULT_PASSPHRASE, Usage: "password for the relay", EnvVars: []string{"CROC_PASS"}},
|
||||
&cli.StringFlag{Name: "socks5", Value: "", Usage: "add a socks5 proxy", EnvVars: []string{"SOCKS5_PROXY"}},
|
||||
&cli.StringFlag{Name: "connect", Value: "", Usage: "add a http proxy", EnvVars: []string{"HTTP_PROXY"}},
|
||||
&cli.StringFlag{Name: "throttleUpload", Value: "", Usage: "Throttle the upload speed e.g. 500k"},
|
||||
}
|
||||
app.EnableBashCompletion = true
|
||||
|
|
@ -133,61 +117,6 @@ func Run() (err error) {
|
|||
return true
|
||||
}
|
||||
|
||||
// check if "classic" is set
|
||||
classicFile := getClassicConfigFile(true)
|
||||
classicInsecureMode := utils.Exists(classicFile)
|
||||
if c.Bool("classic") {
|
||||
if classicInsecureMode {
|
||||
// classic mode not enabled
|
||||
fmt.Print(`Classic mode is currently ENABLED.
|
||||
|
||||
Disabling this mode will prevent the shared secret from being visible
|
||||
on the host's process list when passed via the command line. On a
|
||||
multi-user system, this will help ensure that other local users cannot
|
||||
access the shared secret and receive the files instead of the intended
|
||||
recipient.
|
||||
|
||||
Do you wish to continue to DISABLE the classic mode? (y/N) `)
|
||||
choice := strings.ToLower(utils.GetInput(""))
|
||||
if choice == "y" || choice == "yes" {
|
||||
os.Remove(classicFile)
|
||||
fmt.Print("\nClassic mode DISABLED.\n\n")
|
||||
fmt.Print(`To send and receive, export the CROC_SECRET variable with the code phrase:
|
||||
|
||||
Send: CROC_SECRET=*** croc send file.txt
|
||||
|
||||
Receive: CROC_SECRET=*** croc` + "\n\n")
|
||||
} else {
|
||||
fmt.Print("\nClassic mode ENABLED.\n")
|
||||
|
||||
}
|
||||
} else {
|
||||
// enable classic mode
|
||||
// touch the file
|
||||
fmt.Print(`Classic mode is currently DISABLED.
|
||||
|
||||
Please note that enabling this mode will make the shared secret visible
|
||||
on the host's process list when passed via the command line. On a
|
||||
multi-user system, this could allow other local users to access the
|
||||
shared secret and receive the files instead of the intended recipient.
|
||||
|
||||
Do you wish to continue to enable the classic mode? (y/N) `)
|
||||
choice := strings.ToLower(utils.GetInput(""))
|
||||
if choice == "y" || choice == "yes" {
|
||||
fmt.Print("\nClassic mode ENABLED.\n\n")
|
||||
os.WriteFile(classicFile, []byte("enabled"), 0o644)
|
||||
fmt.Print(`To send and receive, use the code phrase:
|
||||
|
||||
Send: croc send --code *** file.txt
|
||||
|
||||
Receive: croc ***` + "\n\n")
|
||||
} else {
|
||||
fmt.Print("\nClassic mode DISABLED.\n")
|
||||
}
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// if trying to send but forgot send, let the user know
|
||||
if c.Args().Present() && allStringsAreFiles(c.Args().Slice()) {
|
||||
fnames := []string{}
|
||||
|
|
@ -201,7 +130,6 @@ Do you wish to continue to enable the classic mode? (y/N) `)
|
|||
return send(c)
|
||||
}
|
||||
}
|
||||
|
||||
return receive(c)
|
||||
}
|
||||
|
||||
|
|
@ -212,21 +140,13 @@ func setDebugLevel(c *cli.Context) {
|
|||
if c.Bool("debug") {
|
||||
log.SetLevel("debug")
|
||||
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 {
|
||||
log.SetLevel("info")
|
||||
}
|
||||
}
|
||||
|
||||
func getSendConfigFile(requireValidPath bool) string {
|
||||
configFile, err := utils.GetConfigDir(requireValidPath)
|
||||
func getConfigFile() string {
|
||||
configFile, err := utils.GetConfigDir()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
|
|
@ -234,24 +154,6 @@ func getSendConfigFile(requireValidPath bool) string {
|
|||
return path.Join(configFile, "send.json")
|
||||
}
|
||||
|
||||
func getClassicConfigFile(requireValidPath bool) string {
|
||||
configFile, err := utils.GetConfigDir(requireValidPath)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
}
|
||||
return path.Join(configFile, "classic_enabled")
|
||||
}
|
||||
|
||||
func getReceiveConfigFile(requireValidPath bool) (string, error) {
|
||||
configFile, err := utils.GetConfigDir(requireValidPath)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return "", err
|
||||
}
|
||||
return path.Join(configFile, "receive.json"), nil
|
||||
}
|
||||
|
||||
func determinePass(c *cli.Context) (pass string) {
|
||||
pass = c.String("pass")
|
||||
b, err := os.ReadFile(pass)
|
||||
|
|
@ -264,54 +166,35 @@ func determinePass(c *cli.Context) (pass string) {
|
|||
func send(c *cli.Context) (err error) {
|
||||
setDebugLevel(c)
|
||||
comm.Socks5Proxy = c.String("socks5")
|
||||
comm.HttpProxy = c.String("connect")
|
||||
|
||||
portParam := c.Int("port")
|
||||
if portParam == 0 {
|
||||
portParam = 9009
|
||||
}
|
||||
transfersParam := c.Int("transfers")
|
||||
if transfersParam == 0 {
|
||||
transfersParam = 4
|
||||
}
|
||||
|
||||
ports := make([]string, transfersParam+1)
|
||||
for i := 0; i <= transfersParam; i++ {
|
||||
ports[i] = strconv.Itoa(portParam + i)
|
||||
}
|
||||
|
||||
crocOptions := croc.Options{
|
||||
SharedSecret: c.String("code"),
|
||||
IsSender: true,
|
||||
Debug: c.Bool("debug"),
|
||||
NoPrompt: c.Bool("yes"),
|
||||
RelayAddress: c.String("relay"),
|
||||
RelayAddress6: c.String("relay6"),
|
||||
Stdout: c.Bool("stdout"),
|
||||
DisableLocal: c.Bool("no-local"),
|
||||
OnlyLocal: c.Bool("local"),
|
||||
IgnoreStdin: c.Bool("ignore-stdin"),
|
||||
RelayPorts: ports,
|
||||
Ask: c.Bool("ask"),
|
||||
NoMultiplexing: c.Bool("no-multi"),
|
||||
RelayPassword: determinePass(c),
|
||||
SendingText: c.String("text") != "",
|
||||
NoCompress: c.Bool("no-compress"),
|
||||
Overwrite: c.Bool("overwrite"),
|
||||
Curve: c.String("curve"),
|
||||
HashAlgorithm: c.String("hash"),
|
||||
ThrottleUpload: c.String("throttleUpload"),
|
||||
ZipFolder: c.Bool("zip"),
|
||||
GitIgnore: c.Bool("git"),
|
||||
ShowQrCode: c.Bool("qrcode"),
|
||||
MulticastAddress: c.String("multicast"),
|
||||
SharedSecret: c.String("code"),
|
||||
IsSender: true,
|
||||
Debug: c.Bool("debug"),
|
||||
NoPrompt: c.Bool("yes"),
|
||||
RelayAddress: c.String("relay"),
|
||||
RelayAddress6: c.String("relay6"),
|
||||
Stdout: c.Bool("stdout"),
|
||||
DisableLocal: c.Bool("no-local"),
|
||||
OnlyLocal: c.Bool("local"),
|
||||
IgnoreStdin: c.Bool("ignore-stdin"),
|
||||
RelayPorts: strings.Split(c.String("ports"), ","),
|
||||
Ask: c.Bool("ask"),
|
||||
NoMultiplexing: c.Bool("no-multi"),
|
||||
RelayPassword: determinePass(c),
|
||||
SendingText: c.String("text") != "",
|
||||
NoCompress: c.Bool("no-compress"),
|
||||
Overwrite: c.Bool("overwrite"),
|
||||
Curve: c.String("curve"),
|
||||
HashAlgorithm: c.String("hash"),
|
||||
ThrottleUpload: c.String("throttleUpload"),
|
||||
ZipFolder: c.Bool("zip"),
|
||||
}
|
||||
if crocOptions.RelayAddress != models.DEFAULT_RELAY {
|
||||
crocOptions.RelayAddress6 = ""
|
||||
} else if crocOptions.RelayAddress6 != models.DEFAULT_RELAY6 {
|
||||
crocOptions.RelayAddress = ""
|
||||
}
|
||||
b, errOpen := os.ReadFile(getSendConfigFile(false))
|
||||
b, errOpen := os.ReadFile(getConfigFile())
|
||||
if errOpen == nil && !c.Bool("remember") {
|
||||
var rememberedOptions croc.Options
|
||||
err = json.Unmarshal(b, &rememberedOptions)
|
||||
|
|
@ -347,12 +230,6 @@ func send(c *cli.Context) (err error) {
|
|||
if !c.IsSet("local") {
|
||||
crocOptions.OnlyLocal = rememberedOptions.OnlyLocal
|
||||
}
|
||||
if !c.IsSet("hash") {
|
||||
crocOptions.HashAlgorithm = rememberedOptions.HashAlgorithm
|
||||
}
|
||||
if !c.IsSet("git") {
|
||||
crocOptions.GitIgnore = rememberedOptions.GitIgnore
|
||||
}
|
||||
}
|
||||
|
||||
var fnames []string
|
||||
|
|
@ -362,7 +239,6 @@ func send(c *cli.Context) (err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
utils.MarkFileForRemoval(fnames[0])
|
||||
defer func() {
|
||||
e := os.Remove(fnames[0])
|
||||
if e != nil {
|
||||
|
|
@ -374,7 +250,6 @@ func send(c *cli.Context) (err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
utils.MarkFileForRemoval(fnames[0])
|
||||
defer func() {
|
||||
e := os.Remove(fnames[0])
|
||||
if e != nil {
|
||||
|
|
@ -389,36 +264,11 @@ func send(c *cli.Context) (err error) {
|
|||
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 {
|
||||
// generate code phrase
|
||||
crocOptions.SharedSecret = utils.GetRandomName()
|
||||
}
|
||||
minimalFileInfos, emptyFoldersToTransfer, totalNumberFolders, err := croc.GetFilesInfo(fnames, crocOptions.ZipFolder, crocOptions.GitIgnore)
|
||||
minimalFileInfos, emptyFoldersToTransfer, totalNumberFolders, err := croc.GetFilesInfo(fnames, crocOptions.ZipFolder)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -474,7 +324,7 @@ func makeTempFileWithString(s string) (fnames []string, err error) {
|
|||
|
||||
func saveConfig(c *cli.Context, crocOptions croc.Options) {
|
||||
if c.Bool("remember") {
|
||||
configFile := getSendConfigFile(true)
|
||||
configFile := getConfigFile()
|
||||
log.Debug("saving config file")
|
||||
var bConfig []byte
|
||||
// if the code wasn't set, don't save it
|
||||
|
|
@ -486,7 +336,7 @@ func saveConfig(c *cli.Context, crocOptions croc.Options) {
|
|||
log.Error(err)
|
||||
return
|
||||
}
|
||||
err = os.WriteFile(configFile, bConfig, 0o644)
|
||||
err = os.WriteFile(configFile, bConfig, 0644)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
|
|
@ -495,55 +345,22 @@ func saveConfig(c *cli.Context, crocOptions croc.Options) {
|
|||
}
|
||||
}
|
||||
|
||||
type TabComplete struct{}
|
||||
|
||||
func (t TabComplete) Do(line []rune, pos int) ([][]rune, int) {
|
||||
var words = strings.SplitAfter(string(line), "-")
|
||||
var lastPartialWord = words[len(words)-1]
|
||||
var nbCharacter = len(lastPartialWord)
|
||||
if nbCharacter == 0 {
|
||||
// No completion
|
||||
return [][]rune{[]rune("")}, 0
|
||||
}
|
||||
if len(words) == 1 && nbCharacter == utils.NbPinNumbers {
|
||||
// Check if word is indeed a number
|
||||
_, err := strconv.Atoi(lastPartialWord)
|
||||
if err == nil {
|
||||
return [][]rune{[]rune("-")}, nbCharacter
|
||||
}
|
||||
}
|
||||
var strArray [][]rune
|
||||
for _, s := range mnemonicode.WordList {
|
||||
if strings.HasPrefix(s, lastPartialWord) {
|
||||
var completionCandidate = s[nbCharacter:]
|
||||
if len(words) <= mnemonicode.WordsRequired(utils.NbBytesWords) {
|
||||
completionCandidate += "-"
|
||||
}
|
||||
strArray = append(strArray, []rune(completionCandidate))
|
||||
}
|
||||
}
|
||||
return strArray, nbCharacter
|
||||
}
|
||||
|
||||
func receive(c *cli.Context) (err error) {
|
||||
comm.Socks5Proxy = c.String("socks5")
|
||||
comm.HttpProxy = c.String("connect")
|
||||
crocOptions := croc.Options{
|
||||
SharedSecret: c.String("code"),
|
||||
IsSender: false,
|
||||
Debug: c.Bool("debug"),
|
||||
NoPrompt: c.Bool("yes"),
|
||||
RelayAddress: c.String("relay"),
|
||||
RelayAddress6: c.String("relay6"),
|
||||
Stdout: c.Bool("stdout"),
|
||||
Ask: c.Bool("ask"),
|
||||
RelayPassword: determinePass(c),
|
||||
OnlyLocal: c.Bool("local"),
|
||||
IP: c.String("ip"),
|
||||
Overwrite: c.Bool("overwrite"),
|
||||
Curve: c.String("curve"),
|
||||
TestFlag: c.Bool("testing"),
|
||||
MulticastAddress: c.String("multicast"),
|
||||
SharedSecret: c.String("code"),
|
||||
IsSender: false,
|
||||
Debug: c.Bool("debug"),
|
||||
NoPrompt: c.Bool("yes"),
|
||||
RelayAddress: c.String("relay"),
|
||||
RelayAddress6: c.String("relay6"),
|
||||
Stdout: c.Bool("stdout"),
|
||||
Ask: c.Bool("ask"),
|
||||
RelayPassword: determinePass(c),
|
||||
OnlyLocal: c.Bool("local"),
|
||||
IP: c.String("ip"),
|
||||
Overwrite: c.Bool("overwrite"),
|
||||
Curve: c.String("curve"),
|
||||
}
|
||||
if crocOptions.RelayAddress != models.DEFAULT_RELAY {
|
||||
crocOptions.RelayAddress6 = ""
|
||||
|
|
@ -555,8 +372,6 @@ func receive(c *cli.Context) (err error) {
|
|||
case 1:
|
||||
crocOptions.SharedSecret = c.Args().First()
|
||||
case 3:
|
||||
fallthrough
|
||||
case 4:
|
||||
var phrase []string
|
||||
phrase = append(phrase, c.Args().First())
|
||||
phrase = append(phrase, c.Args().Tail()...)
|
||||
|
|
@ -565,14 +380,14 @@ func receive(c *cli.Context) (err error) {
|
|||
|
||||
// load options here
|
||||
setDebugLevel(c)
|
||||
|
||||
doRemember := c.Bool("remember")
|
||||
configFile, err := getReceiveConfigFile(doRemember)
|
||||
if err != nil && doRemember {
|
||||
configFile, err := utils.GetConfigDir()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
configFile = path.Join(configFile, "receive.json")
|
||||
b, errOpen := os.ReadFile(configFile)
|
||||
if errOpen == nil && !doRemember {
|
||||
if errOpen == nil && !c.Bool("remember") {
|
||||
var rememberedOptions croc.Options
|
||||
err = json.Unmarshal(b, &rememberedOptions)
|
||||
if err != nil {
|
||||
|
|
@ -606,43 +421,8 @@ 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 == "" {
|
||||
l, err := readline.NewEx(&readline.Config{
|
||||
Prompt: "Enter receive code: ",
|
||||
AutoComplete: TabComplete{},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
crocOptions.SharedSecret, err = l.Readline()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
crocOptions.SharedSecret = utils.GetInput("Enter receive code: ")
|
||||
}
|
||||
if c.String("out") != "" {
|
||||
if err = os.Chdir(c.String("out")); err != nil {
|
||||
|
|
@ -656,7 +436,7 @@ Or you can go back to the classic croc behavior by enabling classic mode:
|
|||
}
|
||||
|
||||
// save the config
|
||||
if doRemember {
|
||||
if c.Bool("remember") {
|
||||
log.Debug("saving config file")
|
||||
var bConfig []byte
|
||||
bConfig, err = json.MarshalIndent(crocOptions, "", " ")
|
||||
|
|
@ -664,7 +444,7 @@ Or you can go back to the classic croc behavior by enabling classic mode:
|
|||
log.Error(err)
|
||||
return
|
||||
}
|
||||
err = os.WriteFile(configFile, bConfig, 0o644)
|
||||
err = os.WriteFile(configFile, bConfig, 0644)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
|
|
@ -683,32 +463,14 @@ func relay(c *cli.Context) (err error) {
|
|||
debugString = "debug"
|
||||
}
|
||||
host := c.String("host")
|
||||
var ports []string
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
ports := strings.Split(c.String("ports"), ",")
|
||||
tcpPorts := strings.Join(ports[1:], ",")
|
||||
for i, port := range ports {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
go func(portStr string) {
|
||||
err := tcp.Run(debugString, host, portStr, determinePass(c))
|
||||
err = tcp.Run(debugString, host, portStr, determinePass(c))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,12 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/magisterquis/connectproxy"
|
||||
"github.com/schollz/croc/v10/src/utils"
|
||||
"github.com/schollz/croc/v9/src/utils"
|
||||
log "github.com/schollz/logger"
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
var Socks5Proxy = ""
|
||||
var HttpProxy = ""
|
||||
|
||||
var MAGIC_BYTES = []byte("croc")
|
||||
|
||||
|
|
@ -41,7 +39,7 @@ func NewConnection(address string, timelimit ...time.Duration) (c *Comm, err err
|
|||
}
|
||||
socks5ProxyURL, urlParseError := url.Parse(Socks5Proxy)
|
||||
if urlParseError != nil {
|
||||
err = fmt.Errorf("unable to parse socks proxy url: %s", urlParseError)
|
||||
err = fmt.Errorf("Unable to parse socks proxy url: %s", urlParseError)
|
||||
log.Debug(err)
|
||||
return
|
||||
}
|
||||
|
|
@ -53,27 +51,6 @@ func NewConnection(address string, timelimit ...time.Duration) (c *Comm, err err
|
|||
}
|
||||
log.Debug("dialing with dialer.Dial")
|
||||
connection, err = dialer.Dial("tcp", address)
|
||||
} else if HttpProxy != "" && !utils.IsLocalIP(address) {
|
||||
var dialer proxy.Dialer
|
||||
// prepend schema if no schema is given
|
||||
if !strings.Contains(HttpProxy, `://`) {
|
||||
HttpProxy = `http://` + HttpProxy
|
||||
}
|
||||
HttpProxyURL, urlParseError := url.Parse(HttpProxy)
|
||||
if urlParseError != nil {
|
||||
err = fmt.Errorf("unable to parse http proxy url: %s", urlParseError)
|
||||
log.Debug(err)
|
||||
return
|
||||
}
|
||||
dialer, err = connectproxy.New(HttpProxyURL, proxy.Direct)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("proxy failed: %w", err)
|
||||
log.Debug(err)
|
||||
return
|
||||
}
|
||||
log.Debug("dialing with dialer.Dial")
|
||||
connection, err = dialer.Dial("tcp", address)
|
||||
|
||||
} else {
|
||||
log.Debugf("dialing to %s with timelimit %s", address, tlimit)
|
||||
connection, err = net.DialTimeout("tcp", address, tlimit)
|
||||
|
|
@ -138,7 +115,7 @@ func (c *Comm) Write(b []byte) (n int, err error) {
|
|||
|
||||
func (c *Comm) Read() (buf []byte, numBytes int, bs []byte, err error) {
|
||||
// long read deadline in case waiting for file
|
||||
if err = c.connection.SetReadDeadline(time.Now().Add(3 * time.Hour)); err != nil {
|
||||
if err := c.connection.SetReadDeadline(time.Now().Add(3 * time.Hour)); err != nil {
|
||||
log.Warnf("error setting read deadline: %v", err)
|
||||
}
|
||||
// must clear the timeout setting
|
||||
|
|
@ -175,7 +152,7 @@ func (c *Comm) Read() (buf []byte, numBytes int, bs []byte, err error) {
|
|||
numBytes = int(numBytesUint32)
|
||||
|
||||
// shorten the reading deadline in case getting weird data
|
||||
if err = c.connection.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
|
||||
if err := c.connection.SetReadDeadline(time.Now().Add(10 * time.Second)); err != nil {
|
||||
log.Warnf("error setting read deadline: %v", err)
|
||||
}
|
||||
buf = make([]byte, numBytes)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func TestComm(t *testing.T) {
|
|||
log.Error(err)
|
||||
}
|
||||
log.Debugf("client %s connected", connection.RemoteAddr().String())
|
||||
go func(_ string, connection net.Conn) {
|
||||
go func(port string, connection net.Conn) {
|
||||
c := New(connection)
|
||||
err = c.Send([]byte("hello, world"))
|
||||
assert.Nil(t, err)
|
||||
|
|
@ -49,7 +49,7 @@ func TestComm(t *testing.T) {
|
|||
}()
|
||||
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
a, err := NewConnection("127.0.0.1:"+port, 10*time.Minute)
|
||||
a, err := NewConnection("localhost:"+port, 10*time.Minute)
|
||||
assert.Nil(t, err)
|
||||
data, err := a.Receive()
|
||||
assert.Equal(t, []byte("hello, world"), data)
|
||||
|
|
@ -63,4 +63,5 @@ func TestComm(t *testing.T) {
|
|||
assert.NotNil(t, a.Send(token))
|
||||
_, err = a.Write(token)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
}
|
||||
|
|
|
|||
679
src/croc/croc.go
679
src/croc/croc.go
File diff suppressed because it is too large
Load Diff
|
|
@ -5,12 +5,11 @@ import (
|
|||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/schollz/croc/v10/src/tcp"
|
||||
"github.com/schollz/croc/v9/src/tcp"
|
||||
log "github.com/schollz/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -18,11 +17,11 @@ import (
|
|||
func init() {
|
||||
log.SetLevel("trace")
|
||||
|
||||
go tcp.Run("debug", "127.0.0.1", "8281", "pass123", "8282,8283,8284,8285")
|
||||
go tcp.Run("debug", "127.0.0.1", "8282", "pass123")
|
||||
go tcp.Run("debug", "127.0.0.1", "8283", "pass123")
|
||||
go tcp.Run("debug", "127.0.0.1", "8284", "pass123")
|
||||
go tcp.Run("debug", "127.0.0.1", "8285", "pass123")
|
||||
go tcp.Run("debug", "localhost", "8281", "pass123", "8282,8283,8284,8285")
|
||||
go tcp.Run("debug", "localhost", "8282", "pass123")
|
||||
go tcp.Run("debug", "localhost", "8283", "pass123")
|
||||
go tcp.Run("debug", "localhost", "8284", "pass123")
|
||||
go tcp.Run("debug", "localhost", "8285", "pass123")
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +33,7 @@ func TestCrocReadme(t *testing.T) {
|
|||
IsSender: true,
|
||||
SharedSecret: "8123-testingthecroc",
|
||||
Debug: true,
|
||||
RelayAddress: "127.0.0.1:8281",
|
||||
RelayAddress: "localhost:8281",
|
||||
RelayPorts: []string{"8281"},
|
||||
RelayPassword: "pass123",
|
||||
Stdout: false,
|
||||
|
|
@ -42,7 +41,6 @@ func TestCrocReadme(t *testing.T) {
|
|||
DisableLocal: true,
|
||||
Curve: "siec",
|
||||
Overwrite: true,
|
||||
GitIgnore: false,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -53,7 +51,7 @@ func TestCrocReadme(t *testing.T) {
|
|||
IsSender: false,
|
||||
SharedSecret: "8123-testingthecroc",
|
||||
Debug: true,
|
||||
RelayAddress: "127.0.0.1:8281",
|
||||
RelayAddress: "localhost:8281",
|
||||
RelayPassword: "pass123",
|
||||
Stdout: false,
|
||||
NoPrompt: true,
|
||||
|
|
@ -68,7 +66,7 @@ func TestCrocReadme(t *testing.T) {
|
|||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{"../../README.md"}, false, false)
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{"../../README.md"}, false)
|
||||
if errGet != nil {
|
||||
t.Errorf("failed to get minimal info: %v", errGet)
|
||||
}
|
||||
|
|
@ -94,14 +92,14 @@ func TestCrocEmptyFolder(t *testing.T) {
|
|||
pathName := "../../testEmpty"
|
||||
defer os.RemoveAll(pathName)
|
||||
defer os.RemoveAll("./testEmpty")
|
||||
os.MkdirAll(pathName, 0o755)
|
||||
os.MkdirAll(pathName, 0755)
|
||||
|
||||
log.Debug("setting up sender")
|
||||
sender, err := New(Options{
|
||||
IsSender: true,
|
||||
SharedSecret: "8123-testingthecroc",
|
||||
Debug: true,
|
||||
RelayAddress: "127.0.0.1:8281",
|
||||
RelayAddress: "localhost:8281",
|
||||
RelayPorts: []string{"8281"},
|
||||
RelayPassword: "pass123",
|
||||
Stdout: false,
|
||||
|
|
@ -119,7 +117,7 @@ func TestCrocEmptyFolder(t *testing.T) {
|
|||
IsSender: false,
|
||||
SharedSecret: "8123-testingthecroc",
|
||||
Debug: true,
|
||||
RelayAddress: "127.0.0.1:8281",
|
||||
RelayAddress: "localhost:8281",
|
||||
RelayPassword: "pass123",
|
||||
Stdout: false,
|
||||
NoPrompt: true,
|
||||
|
|
@ -134,7 +132,7 @@ func TestCrocEmptyFolder(t *testing.T) {
|
|||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{pathName}, false, false)
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{pathName}, false)
|
||||
if errGet != nil {
|
||||
t.Errorf("failed to get minimal info: %v", errGet)
|
||||
}
|
||||
|
|
@ -160,7 +158,7 @@ func TestCrocSymlink(t *testing.T) {
|
|||
pathName := "../link-in-folder"
|
||||
defer os.RemoveAll(pathName)
|
||||
defer os.RemoveAll("./link-in-folder")
|
||||
os.MkdirAll(pathName, 0o755)
|
||||
os.MkdirAll(pathName, 0755)
|
||||
os.Symlink("../../README.md", filepath.Join(pathName, "README.link"))
|
||||
|
||||
log.Debug("setting up sender")
|
||||
|
|
@ -168,7 +166,7 @@ func TestCrocSymlink(t *testing.T) {
|
|||
IsSender: true,
|
||||
SharedSecret: "8124-testingthecroc",
|
||||
Debug: true,
|
||||
RelayAddress: "127.0.0.1:8281",
|
||||
RelayAddress: "localhost:8281",
|
||||
RelayPorts: []string{"8281"},
|
||||
RelayPassword: "pass123",
|
||||
Stdout: false,
|
||||
|
|
@ -176,7 +174,6 @@ func TestCrocSymlink(t *testing.T) {
|
|||
DisableLocal: true,
|
||||
Curve: "siec",
|
||||
Overwrite: true,
|
||||
GitIgnore: false,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -187,7 +184,7 @@ func TestCrocSymlink(t *testing.T) {
|
|||
IsSender: false,
|
||||
SharedSecret: "8124-testingthecroc",
|
||||
Debug: true,
|
||||
RelayAddress: "127.0.0.1:8281",
|
||||
RelayAddress: "localhost:8281",
|
||||
RelayPassword: "pass123",
|
||||
Stdout: false,
|
||||
NoPrompt: true,
|
||||
|
|
@ -202,11 +199,11 @@ func TestCrocSymlink(t *testing.T) {
|
|||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{pathName}, false, false)
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{pathName}, false)
|
||||
if errGet != nil {
|
||||
t.Errorf("failed to get minimal info: %v", errGet)
|
||||
}
|
||||
err = sender.Send(filesInfo, emptyFolders, totalNumberFolders)
|
||||
err := sender.Send(filesInfo, emptyFolders, totalNumberFolders)
|
||||
if err != nil {
|
||||
t.Errorf("send failed: %v", err)
|
||||
}
|
||||
|
|
@ -214,7 +211,7 @@ func TestCrocSymlink(t *testing.T) {
|
|||
}()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
go func() {
|
||||
err = receiver.Receive()
|
||||
err := receiver.Receive()
|
||||
if err != nil {
|
||||
t.Errorf("receive failed: %v", err)
|
||||
}
|
||||
|
|
@ -232,32 +229,6 @@ func TestCrocSymlink(t *testing.T) {
|
|||
t.Errorf("symlink transfer failed: %s", err.Error())
|
||||
}
|
||||
}
|
||||
func TestCrocIgnoreGit(t *testing.T) {
|
||||
log.SetLevel("trace")
|
||||
defer os.Remove(".gitignore")
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
file, err := os.Create(".gitignore")
|
||||
if err != nil {
|
||||
log.Errorf("error creating file")
|
||||
}
|
||||
_, err = file.WriteString("LICENSE")
|
||||
if err != nil {
|
||||
log.Errorf("error writing to file")
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
// due to how files are ignored in this function, all we have to do to test is make sure LICENSE doesn't get included in FilesInfo.
|
||||
filesInfo, _, _, errGet := GetFilesInfo([]string{"../../LICENSE", ".gitignore", "croc.go"}, false, true)
|
||||
if errGet != nil {
|
||||
t.Errorf("failed to get minimal info: %v", errGet)
|
||||
}
|
||||
for _, file := range filesInfo {
|
||||
if strings.Contains(file.Name, "LICENSE") {
|
||||
t.Errorf("test failed, should ignore LICENSE")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrocLocal(t *testing.T) {
|
||||
log.SetLevel("trace")
|
||||
|
|
@ -270,7 +241,7 @@ func TestCrocLocal(t *testing.T) {
|
|||
IsSender: true,
|
||||
SharedSecret: "8123-testingthecroc",
|
||||
Debug: true,
|
||||
RelayAddress: "127.0.0.1:8181",
|
||||
RelayAddress: "localhost:8181",
|
||||
RelayPorts: []string{"8181", "8182"},
|
||||
RelayPassword: "pass123",
|
||||
Stdout: true,
|
||||
|
|
@ -278,7 +249,6 @@ func TestCrocLocal(t *testing.T) {
|
|||
DisableLocal: false,
|
||||
Curve: "siec",
|
||||
Overwrite: true,
|
||||
GitIgnore: false,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -290,7 +260,7 @@ func TestCrocLocal(t *testing.T) {
|
|||
IsSender: false,
|
||||
SharedSecret: "8123-testingthecroc",
|
||||
Debug: true,
|
||||
RelayAddress: "127.0.0.1:8181",
|
||||
RelayAddress: "localhost:8181",
|
||||
RelayPassword: "pass123",
|
||||
Stdout: true,
|
||||
NoPrompt: true,
|
||||
|
|
@ -306,7 +276,7 @@ func TestCrocLocal(t *testing.T) {
|
|||
os.Create("touched")
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{"../../LICENSE", "touched"}, false, false)
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{"../../LICENSE", "touched"}, false)
|
||||
if errGet != nil {
|
||||
t.Errorf("failed to get minimal info: %v", errGet)
|
||||
}
|
||||
|
|
@ -337,10 +307,10 @@ func TestCrocError(t *testing.T) {
|
|||
|
||||
defer os.Remove(tmpfile.Name()) // clean up
|
||||
|
||||
if _, err = tmpfile.Write(content); err != nil {
|
||||
if _, err := tmpfile.Write(content); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tmpfile.Close(); err != nil {
|
||||
if err := tmpfile.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
|
@ -359,7 +329,7 @@ func TestCrocError(t *testing.T) {
|
|||
Curve: "siec",
|
||||
Overwrite: true,
|
||||
})
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{tmpfile.Name()}, false, false)
|
||||
filesInfo, emptyFolders, totalNumberFolders, errGet := GetFilesInfo([]string{tmpfile.Name()}, false)
|
||||
if errGet != nil {
|
||||
t.Errorf("failed to get minimal info: %v", errGet)
|
||||
}
|
||||
|
|
@ -383,7 +353,7 @@ func TestCleanUp(t *testing.T) {
|
|||
for _, file := range []string{"README.md", "./README.md"} {
|
||||
err = os.Remove(file)
|
||||
if err == nil {
|
||||
log.Debugf("Successfully purged %s", file)
|
||||
log.Debugf("Successfuly purged %s", file)
|
||||
} else {
|
||||
log.Debugf("%s was already purged.", file)
|
||||
}
|
||||
|
|
@ -391,7 +361,7 @@ func TestCleanUp(t *testing.T) {
|
|||
for _, folder := range []string{"./testEmpty", "./link-in-folder"} {
|
||||
err = os.RemoveAll(folder)
|
||||
if err == nil {
|
||||
log.Debugf("Successfully purged %s", folder)
|
||||
log.Debugf("Successfuly purged %s", folder)
|
||||
} else {
|
||||
log.Debugf("%s was already purged.", folder)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ func Encrypt(plaintext []byte, key []byte) (encrypted []byte, err error) {
|
|||
// http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
|
||||
// Section 8.2
|
||||
ivBytes := make([]byte, 12)
|
||||
if _, err = rand.Read(ivBytes); err != nil {
|
||||
if _, err := rand.Read(ivBytes); err != nil {
|
||||
log.Fatalf("can't initialize crypto: %v", err)
|
||||
}
|
||||
b, err := aes.NewCipher(key)
|
||||
|
|
@ -85,7 +85,7 @@ func NewArgon2(passphrase []byte, usersalt []byte) (aead cipher.AEAD, salt []byt
|
|||
salt = make([]byte, 8)
|
||||
// http://www.ietf.org/rfc/rfc2898.txt
|
||||
// Salt.
|
||||
if _, err = rand.Read(salt); err != nil {
|
||||
if _, err := rand.Read(salt); err != nil {
|
||||
log.Fatalf("can't get random salt: %v", err)
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
bob, _, _ := NewArgon2([]byte("password"), nil)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
|
@ -66,19 +52,19 @@ func TestEncryption(t *testing.T) {
|
|||
assert.Equal(t, msg, dec)
|
||||
|
||||
// check reusing the salt
|
||||
key2, _, _ := New([]byte("password"), salt)
|
||||
key2, _, err := New([]byte("password"), salt)
|
||||
dec, err = Decrypt(enc, key2)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, msg, dec)
|
||||
|
||||
// check reusing the salt
|
||||
key2, _, _ = New([]byte("wrong password"), salt)
|
||||
key2, _, err = New([]byte("wrong password"), salt)
|
||||
dec, err = Decrypt(enc, key2)
|
||||
assert.NotNil(t, err)
|
||||
assert.NotEqual(t, msg, dec)
|
||||
|
||||
// error with no password
|
||||
_, err = Decrypt([]byte(""), key)
|
||||
dec, err = Decrypt([]byte(""), key)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// error with small password
|
||||
|
|
@ -98,19 +84,19 @@ func TestEncryptionChaCha(t *testing.T) {
|
|||
assert.Equal(t, msg, dec)
|
||||
|
||||
// check reusing the salt
|
||||
key2, _, _ := NewArgon2([]byte("password"), salt)
|
||||
key2, _, err := NewArgon2([]byte("password"), salt)
|
||||
dec, err = DecryptChaCha(enc, key2)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, msg, dec)
|
||||
|
||||
// check reusing the salt
|
||||
key2, _, _ = NewArgon2([]byte("wrong password"), salt)
|
||||
key2, _, err = NewArgon2([]byte("wrong password"), salt)
|
||||
dec, err = DecryptChaCha(enc, key2)
|
||||
assert.NotNil(t, err)
|
||||
assert.NotEqual(t, msg, dec)
|
||||
|
||||
// error with no password
|
||||
_, err = DecryptChaCha([]byte(""), key)
|
||||
dec, err = DecryptChaCha([]byte(""), key)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// error with small password
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
@ -13,7 +13,5 @@ release:
|
|||
cd ../../ && ./src/install/upload-src-tarball.sh
|
||||
|
||||
test:
|
||||
cp zsh_autocomplete ../../
|
||||
cp bash_autocomplete ../../
|
||||
cd ../../ && go generate
|
||||
cd ../../ && goreleaser release --skip-publish
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ print_help() {
|
|||
Default = /usr/local/bin ('\${PREFIX}/bin' on Termux for Android)
|
||||
|
||||
-h
|
||||
Prints this helpful message and exit."
|
||||
Prints this helpfull message and exit."
|
||||
|
||||
echo "${help_header}"
|
||||
echo ""
|
||||
|
|
@ -156,7 +156,7 @@ make_tempdir() {
|
|||
|
||||
#--- FUNCTION ----------------------------------------------------------------
|
||||
# NAME: determine_os
|
||||
# DESCRIPTION: Attempts to determine host os using uname
|
||||
# DESCRIPTION: Attempts to determin host os using uname
|
||||
# PARAMETERS: none
|
||||
# RETURNS: 0 = OS Detected. Also prints detected os to stdout
|
||||
# 1 = Unknown OS
|
||||
|
|
@ -180,7 +180,7 @@ determine_os() {
|
|||
|
||||
#--- FUNCTION ----------------------------------------------------------------
|
||||
# NAME: determine_arch
|
||||
# DESCRIPTION: Attempt to determine architecture of host
|
||||
# DESCRIPTION: Attempt to determin architecture of host
|
||||
# PARAMETERS: none
|
||||
# RETURNS: 0 = Arch Detected. Also prints detected arch to stdout
|
||||
# 1 = Unknown arch
|
||||
|
|
@ -300,10 +300,10 @@ checksum_check() {
|
|||
#--- FUNCTION ----------------------------------------------------------------
|
||||
# NAME: extract_file
|
||||
# DESCRIPTION: Extracts a file into a location. Attempts to determine which
|
||||
# tool to use by checking file extension.
|
||||
# tool to use by checking file extention.
|
||||
# PARAMETERS: $1 = file to extract
|
||||
# $2 = location to extract file into
|
||||
# $3 = extension
|
||||
# $3 = extention
|
||||
# RETURNS: Return code of the tool used to extract the file
|
||||
# 20 = Failed to determine which tool to use
|
||||
# 30 = Failed to find tool in path
|
||||
|
|
@ -528,7 +528,7 @@ main() {
|
|||
local autocomplete_install_rcode
|
||||
|
||||
croc_bin_name="croc"
|
||||
croc_version="10.1.1"
|
||||
croc_version="9.6.0"
|
||||
croc_dl_ext="tar.gz"
|
||||
croc_base_url="https://github.com/schollz/croc/releases/download"
|
||||
prefix="${1}"
|
||||
|
|
@ -577,9 +577,6 @@ main() {
|
|||
|
||||
case "${croc_os}" in
|
||||
"Darwin" ) croc_os="macOS";;
|
||||
*"BusyBox"* )
|
||||
croc_os="Linux"
|
||||
;;
|
||||
"CYGWIN"* ) croc_os="Windows";
|
||||
croc_dl_ext="zip";
|
||||
print_message "== Cygwin is currently unsupported." "error";
|
||||
|
|
@ -590,19 +587,16 @@ main() {
|
|||
"x86_64" ) croc_arch="64bit";;
|
||||
"amd64" ) croc_arch="64bit";;
|
||||
"aarch64" ) croc_arch="ARM64";;
|
||||
"arm64" ) croc_arch="ARM64";;
|
||||
"armv7l" ) croc_arch="ARM";;
|
||||
"armv8l" ) croc_arch="ARM";;
|
||||
"armv9l" ) croc_arch="ARM";;
|
||||
"i686" ) croc_arch="32bit";;
|
||||
* ) croc_arch="unknown";;
|
||||
esac
|
||||
|
||||
croc_file="${croc_bin_name}_v${croc_version}_${croc_os}-${croc_arch}.${croc_dl_ext}"
|
||||
croc_checksum_file="${croc_bin_name}_v${croc_version}_checksums.txt"
|
||||
croc_file="${croc_bin_name}_${croc_version}_${croc_os}-${croc_arch}.${croc_dl_ext}"
|
||||
croc_checksum_file="${croc_bin_name}_${croc_version}_checksums.txt"
|
||||
croc_url="${croc_base_url}/v${croc_version}/${croc_file}"
|
||||
croc_checksum_url="${croc_base_url}/v${croc_version}/${croc_checksum_file}"
|
||||
echo "${croc_url}" "${tmpdir}" "${croc_file}"
|
||||
|
||||
download_file "${croc_url}" "${tmpdir}" "${croc_file}"
|
||||
download_file_rcode="${?}"
|
||||
if [[ "${download_file_rcode}" == "0" ]]; then
|
||||
|
|
@ -690,7 +684,7 @@ main() {
|
|||
print_message "== Install prefix already exists. No need to create it." "info"
|
||||
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
|
||||
"Linux" ) install_file_linux "${tmpdir}/${croc_bin_name}" "${prefix}/";
|
||||
install_file_rcode="${?}";;
|
||||
|
|
@ -718,27 +712,27 @@ main() {
|
|||
exit 1
|
||||
fi
|
||||
|
||||
# case "$(basename ${SHELL})" in
|
||||
# "bash" ) install_file_linux "${tmpdir}/${bash_autocomplete_file}" "${bash_autocomplete_prefix}/croc";
|
||||
# autocomplete_install_rcode="${?}";;
|
||||
# "zsh" ) install_file_linux "${tmpdir}/${zsh_autocomplete_file}" "${zsh_autocomplete_prefix}/zsh_autocomplete_croc";
|
||||
# autocomplete_install_rcode="${?}";
|
||||
# print_message "== You will need to add the following to your ~/.zshrc to enable autocompletion" "info";
|
||||
# print_message "\nPROG=croc\n_CLI_ZSH_AUTOCOMPLETE_HACK=1\nsource /etc/zsh/zsh_autocomplete_croc\n" "info";;
|
||||
# *) autocomplete_install_rcode="1";;
|
||||
# esac
|
||||
case "$(basename ${SHELL})" in
|
||||
"bash" ) install_file_linux "${tmpdir}/${bash_autocomplete_file}" "${bash_autocomplete_prefix}/croc";
|
||||
autocomplete_install_rcode="${?}";;
|
||||
"zsh" ) install_file_linux "${tmpdir}/${zsh_autocomplete_file}" "${zsh_autocomplete_prefix}/zsh_autocomplete_croc";
|
||||
autocomplete_install_rcode="${?}";
|
||||
print_message "== You will need to add the following to your ~/.zshrc to enable autocompletion" "info";
|
||||
print_message "\nPROG=croc\n_CLI_ZSH_AUTOCOMPLETE_HACK=1\nsource /etc/zsh/zsh_autocomplete_croc\n" "info";;
|
||||
*) autocomplete_install_rcode="1";;
|
||||
esac
|
||||
|
||||
# if [[ "${autocomplete_install_rcode}" == "0" ]] ; then
|
||||
# print_message "== Installed autocompletions for $(basename "${SHELL}")" "ok"
|
||||
# elif [[ "${autocomplete_install_rcode}" == "1" ]]; then
|
||||
# print_message "== Failed to install ${bash_autocomplete_file}" "error"
|
||||
# elif [[ "${autocomplete_install_rcode}" == "20" ]]; then
|
||||
# print_message "== Failed to locate 'install' command" "error"
|
||||
# elif [[ "${autocomplete_install_rcode}" == "21" ]]; then
|
||||
# print_message "== Failed to locate 'sudo' command" "error"
|
||||
# else
|
||||
# print_message "== Install attempt returned an unexpected value of ${autocomplete_install_rcode}" "error"
|
||||
# fi
|
||||
if [[ "${autocomplete_install_rcode}" == "0" ]] ; then
|
||||
print_message "== Installed autocompletions for $(basename "${SHELL}")" "ok"
|
||||
elif [[ "${autocomplete_install_rcode}" == "1" ]]; then
|
||||
print_message "== Failed to install ${bash_autocomplete_file}" "error"
|
||||
elif [[ "${autocomplete_install_rcode}" == "20" ]]; then
|
||||
print_message "== Failed to locate 'install' command" "error"
|
||||
elif [[ "${autocomplete_install_rcode}" == "21" ]]; then
|
||||
print_message "== Failed to locate 'sudo' command" "error"
|
||||
else
|
||||
print_message "== Install attempt returned an unexpected value of ${autocomplete_install_rcode}" "error"
|
||||
fi
|
||||
|
||||
print_message "== Installation complete" "ok"
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func replaceInFile(fname, start, end, replacement string) (err error) {
|
|||
fmt.Sprintf("%s%s%s", start, replacement, end),
|
||||
1,
|
||||
)
|
||||
err = os.WriteFile(fname, []byte(newF), 0o644)
|
||||
err = os.WriteFile(fname, []byte(newF), 0644)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package message
|
|||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/schollz/croc/v10/src/comm"
|
||||
"github.com/schollz/croc/v10/src/compress"
|
||||
"github.com/schollz/croc/v10/src/crypt"
|
||||
"github.com/schollz/croc/v9/src/comm"
|
||||
"github.com/schollz/croc/v9/src/compress"
|
||||
"github.com/schollz/croc/v9/src/crypt"
|
||||
log "github.com/schollz/logger"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/schollz/croc/v10/src/comm"
|
||||
"github.com/schollz/croc/v10/src/crypt"
|
||||
"github.com/schollz/croc/v9/src/comm"
|
||||
"github.com/schollz/croc/v9/src/crypt"
|
||||
log "github.com/schollz/logger"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
@ -20,7 +20,7 @@ func TestMessage(t *testing.T) {
|
|||
m := Message{Type: TypeMessage, Message: "hello, world"}
|
||||
e, salt, err := crypt.New([]byte("pass"), nil)
|
||||
assert.Nil(t, err)
|
||||
fmt.Println(string(salt))
|
||||
fmt.Println(salt)
|
||||
b, err := Encode(e, m)
|
||||
assert.Nil(t, err)
|
||||
fmt.Printf("%x\n", b)
|
||||
|
|
@ -67,7 +67,7 @@ func TestSend(t *testing.T) {
|
|||
log.Error(err)
|
||||
}
|
||||
log.Debugf("client %s connected", connection.RemoteAddr().String())
|
||||
go func(_ string, connection net.Conn) {
|
||||
go func(port string, connection net.Conn) {
|
||||
c := comm.New(connection)
|
||||
err = c.Send([]byte("hello, world"))
|
||||
assert.Nil(t, err)
|
||||
|
|
@ -84,8 +84,8 @@ func TestSend(t *testing.T) {
|
|||
}
|
||||
}()
|
||||
|
||||
time.Sleep(800 * time.Millisecond)
|
||||
a, err := comm.NewConnection("127.0.0.1:"+port, 10*time.Minute)
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
a, err := comm.NewConnection("localhost:"+port, 10*time.Minute)
|
||||
assert.Nil(t, err)
|
||||
m := Message{Type: TypeMessage, Message: "hello, world"}
|
||||
e, salt, err := crypt.New([]byte("pass"), nil)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/schollz/croc/v10/src/utils"
|
||||
log "github.com/schollz/logger"
|
||||
"github.com/schollz/croc/v9/src/utils"
|
||||
)
|
||||
|
||||
// TCP_BUFFER_SIZE is the maximum packet size
|
||||
|
|
@ -24,8 +22,8 @@ var (
|
|||
INTERNAL_DNS = false
|
||||
)
|
||||
|
||||
// publicDNS are servers to be queried if a local lookup fails
|
||||
var publicDNS = []string{
|
||||
// publicDns are servers to be queried if a local lookup fails
|
||||
var publicDns = []string{
|
||||
"1.0.0.1", // Cloudflare
|
||||
"1.1.1.1", // Cloudflare
|
||||
"[2606:4700:4700::1111]", // Cloudflare
|
||||
|
|
@ -46,8 +44,8 @@ var publicDNS = []string{
|
|||
"[2620:119:53::53]", // Cisco OpenDNS
|
||||
}
|
||||
|
||||
func getConfigFile(requireValidPath bool) (fname string, err error) {
|
||||
configFile, err := utils.GetConfigDir(requireValidPath)
|
||||
func getConfigFile() (fname string, err error) {
|
||||
configFile, err := utils.GetConfigDir()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -56,8 +54,6 @@ func getConfigFile(requireValidPath bool) (fname string, err error) {
|
|||
}
|
||||
|
||||
func init() {
|
||||
log.SetLevel("info")
|
||||
log.SetOutput(os.Stderr)
|
||||
doRemember := false
|
||||
for _, flag := range os.Args {
|
||||
if flag == "--internal-dns" {
|
||||
|
|
@ -70,19 +66,18 @@ func init() {
|
|||
}
|
||||
if doRemember {
|
||||
// save in config file
|
||||
fname, err := getConfigFile(true)
|
||||
fname, err := getConfigFile()
|
||||
if err == nil {
|
||||
f, _ := os.Create(fname)
|
||||
f.Close()
|
||||
}
|
||||
}
|
||||
if !INTERNAL_DNS {
|
||||
fname, err := getConfigFile(false)
|
||||
fname, err := getConfigFile()
|
||||
if err == nil {
|
||||
INTERNAL_DNS = utils.Exists(fname)
|
||||
}
|
||||
}
|
||||
log.Trace("Using internal DNS: ", INTERNAL_DNS)
|
||||
var err error
|
||||
var addr string
|
||||
addr, err = lookup(DEFAULT_RELAY)
|
||||
|
|
@ -91,38 +86,33 @@ func init() {
|
|||
} else {
|
||||
DEFAULT_RELAY = ""
|
||||
}
|
||||
log.Tracef("Default ipv4 relay: %s", addr)
|
||||
addr, err = lookup(DEFAULT_RELAY6)
|
||||
if err == nil {
|
||||
DEFAULT_RELAY6 = net.JoinHostPort(addr, DEFAULT_PORT)
|
||||
} else {
|
||||
DEFAULT_RELAY6 = ""
|
||||
}
|
||||
log.Tracef("Default ipv6 relay: %s", addr)
|
||||
}
|
||||
|
||||
// Resolve a hostname to an IP address using DNS.
|
||||
func lookup(address string) (ipaddress string, err error) {
|
||||
if !INTERNAL_DNS {
|
||||
log.Tracef("Using local DNS to resolve %s", address)
|
||||
return localLookupIP(address)
|
||||
}
|
||||
type Result struct {
|
||||
s string
|
||||
err error
|
||||
}
|
||||
result := make(chan Result, len(publicDNS))
|
||||
for _, dns := range publicDNS {
|
||||
result := make(chan Result, len(publicDns))
|
||||
for _, dns := range publicDns {
|
||||
go func(dns string) {
|
||||
var r Result
|
||||
r.s, r.err = remoteLookupIP(address, dns)
|
||||
log.Tracef("Resolved %s to %s using %s", address, r.s, dns)
|
||||
result <- r
|
||||
}(dns)
|
||||
}
|
||||
for i := 0; i < len(publicDNS); i++ {
|
||||
for i := 0; i < len(publicDns); i++ {
|
||||
ipaddress = (<-result).s
|
||||
log.Tracef("Resolved %s to %s", address, ipaddress)
|
||||
if ipaddress != "" {
|
||||
return
|
||||
}
|
||||
|
|
@ -131,16 +121,9 @@ func lookup(address string) (ipaddress string, err error) {
|
|||
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) {
|
||||
// Create a context with a 500 millisecond timeout
|
||||
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)
|
||||
ip, err := net.LookupHost(address)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -150,17 +133,14 @@ func localLookupIP(address string) (ipaddress string, err error) {
|
|||
|
||||
// remoteLookupIP returns a host's IP address based on a remote DNS server.
|
||||
func remoteLookupIP(address, dns string) (ipaddress string, err error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
r := &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, _ string) (net.Conn, error) {
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
d := new(net.Dialer)
|
||||
return d.DialContext(ctx, network, dns+":53")
|
||||
},
|
||||
}
|
||||
ip, err := r.LookupHost(ctx, address)
|
||||
ip, err := r.LookupHost(context.Background(), address)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
116
src/tcp/tcp.go
116
src/tcp/tcp.go
|
|
@ -11,9 +11,9 @@ import (
|
|||
log "github.com/schollz/logger"
|
||||
"github.com/schollz/pake/v3"
|
||||
|
||||
"github.com/schollz/croc/v10/src/comm"
|
||||
"github.com/schollz/croc/v10/src/crypt"
|
||||
"github.com/schollz/croc/v10/src/models"
|
||||
"github.com/schollz/croc/v9/src/comm"
|
||||
"github.com/schollz/croc/v9/src/crypt"
|
||||
"github.com/schollz/croc/v9/src/models"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
|
|
@ -23,11 +23,6 @@ type server struct {
|
|||
banner string
|
||||
password string
|
||||
rooms roomMap
|
||||
|
||||
roomCleanupInterval time.Duration
|
||||
roomTTL time.Duration
|
||||
|
||||
stopRoomCleanup chan struct{}
|
||||
}
|
||||
|
||||
type roomInfo struct {
|
||||
|
|
@ -44,55 +39,46 @@ type roomMap struct {
|
|||
|
||||
const pingRoom = "pinglkasjdlfjsaldjf"
|
||||
|
||||
// newDefaultServer initializes a new server, with some default configuration options
|
||||
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
|
||||
}
|
||||
var timeToRoomDeletion = 10 * time.Minute
|
||||
|
||||
// RunWithOptionsAsync asynchronously starts a TCP listener.
|
||||
func RunWithOptionsAsync(host, port, password string, opts ...serverOptsFunc) error {
|
||||
s := newDefaultServer()
|
||||
// Run starts a tcp listener, run async
|
||||
func Run(debugLevel, host, port, password string, banner ...string) (err error) {
|
||||
s := new(server)
|
||||
s.host = host
|
||||
s.port = port
|
||||
s.password = password
|
||||
for _, opt := range opts {
|
||||
err := opt(s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not apply optional configurations: %w", err)
|
||||
}
|
||||
s.debugLevel = debugLevel
|
||||
if len(banner) > 0 {
|
||||
s.banner = banner[0]
|
||||
}
|
||||
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) {
|
||||
log.SetLevel(s.debugLevel)
|
||||
|
||||
// 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)
|
||||
|
||||
log.Debugf("starting with password '%s'", s.password)
|
||||
s.rooms.Lock()
|
||||
s.rooms.rooms = make(map[string]roomInfo)
|
||||
s.rooms.Unlock()
|
||||
|
||||
go s.deleteOldRooms()
|
||||
defer s.stopRoomDeletion()
|
||||
// delete old rooms
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(timeToRoomDeletion)
|
||||
var roomsToDelete []string
|
||||
s.rooms.Lock()
|
||||
for room := range s.rooms.rooms {
|
||||
if time.Since(s.rooms.rooms[room].opened) > 3*time.Hour {
|
||||
roomsToDelete = append(roomsToDelete, room)
|
||||
}
|
||||
}
|
||||
s.rooms.Unlock()
|
||||
|
||||
for _, room := range roomsToDelete {
|
||||
s.deleteRoom(room)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = s.run()
|
||||
if err != nil {
|
||||
|
|
@ -107,8 +93,7 @@ func (s *server) run() (err error) {
|
|||
if s.host != "" {
|
||||
ip := net.ParseIP(s.host)
|
||||
if ip == nil {
|
||||
var tcpIP *net.IPAddr
|
||||
tcpIP, err = net.ResolveIPAddr("ip", s.host)
|
||||
tcpIP, err := net.ResolveIPAddr("ip", s.host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -187,39 +172,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}
|
||||
|
||||
func (s *server) clientCommunication(port string, c *comm.Comm) (room string, err error) {
|
||||
|
|
@ -275,7 +227,7 @@ func (s *server) clientCommunication(port string, c *comm.Comm) (room string, er
|
|||
if strings.TrimSpace(string(passwordBytes)) != s.password {
|
||||
err = fmt.Errorf("bad password")
|
||||
enc, _ := crypt.Encrypt([]byte(err.Error()), strongKeyForEncryption)
|
||||
if err = c.Send(enc); err != nil {
|
||||
if err := c.Send(enc); err != nil {
|
||||
return "", fmt.Errorf("send error: %w", err)
|
||||
}
|
||||
return
|
||||
|
|
@ -398,11 +350,11 @@ func (s *server) deleteRoom(room string) {
|
|||
}
|
||||
s.rooms.rooms[room] = roomInfo{first: nil, second: nil}
|
||||
delete(s.rooms.rooms, room)
|
||||
|
||||
}
|
||||
|
||||
// chanFromConn creates a channel from a Conn object, and sends everything it
|
||||
//
|
||||
// Read()s from the socket to the channel.
|
||||
// Read()s from the socket to the channel.
|
||||
func chanFromConn(conn net.Conn) chan []byte {
|
||||
c := make(chan []byte, 1)
|
||||
if err := conn.SetReadDeadline(time.Now().Add(3 * time.Hour)); err != nil {
|
||||
|
|
@ -563,7 +515,7 @@ func ConnectToTCPServer(address, password, room string, timelimit ...time.Durati
|
|||
}
|
||||
banner = strings.Split(string(data), "|||")[0]
|
||||
ipaddr = strings.Split(string(data), "|||")[1]
|
||||
log.Debugf("sending room; %s", room)
|
||||
log.Debug("sending room")
|
||||
bSend, err = crypt.Encrypt([]byte(room), strongKeyForEncryption)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
|
|
|
|||
|
|
@ -12,34 +12,34 @@ import (
|
|||
|
||||
func BenchmarkConnection(b *testing.B) {
|
||||
log.SetLevel("trace")
|
||||
go Run("debug", "127.0.0.1", "8283", "pass123", "8284")
|
||||
go Run("debug", "localhost", "8283", "pass123", "8284")
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c, _, _, _ := ConnectToTCPServer("127.0.0.1:8283", "pass123", fmt.Sprintf("testroom%d", i), 1*time.Minute)
|
||||
c, _, _, _ := ConnectToTCPServer("localhost:8283", "pass123", fmt.Sprintf("testroom%d", i), 1*time.Minute)
|
||||
c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestTCP(t *testing.T) {
|
||||
log.SetLevel("error")
|
||||
timeToRoomDeletion := 100 * time.Millisecond
|
||||
go RunWithOptionsAsync("127.0.0.1", "8381", "pass123", WithBanner("8382"), WithLogLevel("debug"), WithRoomTTL(timeToRoomDeletion))
|
||||
timeToRoomDeletion = 100 * time.Millisecond
|
||||
go Run("debug", "localhost", "8381", "pass123", "8382")
|
||||
time.Sleep(timeToRoomDeletion)
|
||||
err := PingServer("127.0.0.1:8381")
|
||||
err := PingServer("localhost:8381")
|
||||
assert.Nil(t, err)
|
||||
err = PingServer("127.0.0.1:8333")
|
||||
err = PingServer("localhost:8333")
|
||||
assert.NotNil(t, err)
|
||||
|
||||
time.Sleep(timeToRoomDeletion)
|
||||
c1, banner, _, err := ConnectToTCPServer("127.0.0.1:8381", "pass123", "testRoom", 1*time.Minute)
|
||||
c1, banner, _, err := ConnectToTCPServer("localhost:8381", "pass123", "testRoom", 1*time.Minute)
|
||||
assert.Equal(t, banner, "8382")
|
||||
assert.Nil(t, err)
|
||||
c2, _, _, err := ConnectToTCPServer("127.0.0.1:8381", "pass123", "testRoom")
|
||||
c2, _, _, err := ConnectToTCPServer("localhost:8381", "pass123", "testRoom")
|
||||
assert.Nil(t, err)
|
||||
_, _, _, err = ConnectToTCPServer("127.0.0.1:8381", "pass123", "testRoom")
|
||||
_, _, _, err = ConnectToTCPServer("localhost:8381", "pass123", "testRoom")
|
||||
assert.NotNil(t, err)
|
||||
_, _, _, err = ConnectToTCPServer("127.0.0.1:8381", "pass123", "testRoom", 1*time.Nanosecond)
|
||||
_, _, _, err = ConnectToTCPServer("localhost:8381", "pass123", "testRoom", 1*time.Nanosecond)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
// try sending data
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"math/big"
|
||||
"net"
|
||||
|
|
@ -20,41 +21,29 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
"github.com/cespare/xxhash"
|
||||
"github.com/kalafut/imohash"
|
||||
"github.com/minio/highwayhash"
|
||||
"github.com/schollz/croc/v10/src/mnemonicode"
|
||||
log "github.com/schollz/logger"
|
||||
"github.com/schollz/progressbar/v3"
|
||||
"github.com/schollz/mnemonicode"
|
||||
)
|
||||
|
||||
const NbPinNumbers = 4
|
||||
const NbBytesWords = 4
|
||||
|
||||
// Get or create home directory
|
||||
func GetConfigDir(requireValidPath bool) (homedir string, err error) {
|
||||
func GetConfigDir() (homedir string, err error) {
|
||||
homedir, err = os.UserHomeDir()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if envHomedir, isSet := os.LookupEnv("CROC_CONFIG_DIR"); isSet {
|
||||
homedir = envHomedir
|
||||
} else if xdgConfigHome, isSet := os.LookupEnv("XDG_CONFIG_HOME"); isSet {
|
||||
homedir = path.Join(xdgConfigHome, "croc")
|
||||
} else {
|
||||
homedir, err = os.UserHomeDir()
|
||||
if err != nil {
|
||||
if !requireValidPath {
|
||||
err = nil
|
||||
homedir = ""
|
||||
}
|
||||
return
|
||||
}
|
||||
homedir = path.Join(homedir, ".config", "croc")
|
||||
}
|
||||
|
||||
if requireValidPath {
|
||||
if _, err = os.Stat(homedir); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(homedir, 0o700)
|
||||
}
|
||||
if _, err = os.Stat(homedir); os.IsNotExist(err) {
|
||||
err = os.MkdirAll(homedir, 0700)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -79,11 +68,7 @@ func GetInput(prompt string) string {
|
|||
|
||||
// HashFile returns the hash of a file or, in case of a symlink, the
|
||||
// SHA256 hash of its target. Takes an argument to specify the algorithm to use.
|
||||
func HashFile(fname string, algorithm string, showProgress ...bool) (hash256 []byte, err error) {
|
||||
doShowProgress := false
|
||||
if len(showProgress) > 0 {
|
||||
doShowProgress = showProgress[0]
|
||||
}
|
||||
func HashFile(fname string, algorithm string) (hash256 []byte, err error) {
|
||||
var fstats os.FileInfo
|
||||
fstats, err = os.Lstat(fname)
|
||||
if err != nil {
|
||||
|
|
@ -101,59 +86,16 @@ func HashFile(fname string, algorithm string, showProgress ...bool) (hash256 []b
|
|||
case "imohash":
|
||||
return IMOHashFile(fname)
|
||||
case "md5":
|
||||
return MD5HashFile(fname, doShowProgress)
|
||||
return MD5HashFile(fname)
|
||||
case "xxhash":
|
||||
return XXHashFile(fname, doShowProgress)
|
||||
case "highway":
|
||||
return HighwayHashFile(fname, doShowProgress)
|
||||
return XXHashFile(fname)
|
||||
}
|
||||
err = fmt.Errorf("unspecified algorithm")
|
||||
return
|
||||
}
|
||||
|
||||
// HighwayHashFile returns highwayhash of a file
|
||||
func HighwayHashFile(fname string, doShowProgress bool) (hashHighway []byte, err error) {
|
||||
f, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
key, err := hex.DecodeString("1553c5383fb0b86578c3310da665b4f6e0521acf22eb58a99532ffed02a6b115")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
h, err := highwayhash.New(key)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not create highwayhash: %s", err.Error())
|
||||
return
|
||||
}
|
||||
if doShowProgress {
|
||||
stat, _ := f.Stat()
|
||||
fnameShort := path.Base(fname)
|
||||
if len(fnameShort) > 20 {
|
||||
fnameShort = fnameShort[:20] + "..."
|
||||
}
|
||||
bar := progressbar.NewOptions64(stat.Size(),
|
||||
progressbar.OptionSetWriter(os.Stderr),
|
||||
progressbar.OptionShowBytes(true),
|
||||
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
|
||||
progressbar.OptionClearOnFinish(),
|
||||
)
|
||||
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if _, err = io.Copy(h, f); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
hashHighway = h.Sum(nil)
|
||||
return
|
||||
}
|
||||
|
||||
// MD5HashFile returns MD5 hash
|
||||
func MD5HashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
|
||||
func MD5HashFile(fname string) (hash256 []byte, err error) {
|
||||
f, err := os.Open(fname)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -161,41 +103,23 @@ func MD5HashFile(fname string, doShowProgress bool) (hash256 []byte, err error)
|
|||
defer f.Close()
|
||||
|
||||
h := md5.New()
|
||||
if doShowProgress {
|
||||
stat, _ := f.Stat()
|
||||
fnameShort := path.Base(fname)
|
||||
if len(fnameShort) > 20 {
|
||||
fnameShort = fnameShort[:20] + "..."
|
||||
}
|
||||
bar := progressbar.NewOptions64(stat.Size(),
|
||||
progressbar.OptionSetWriter(os.Stderr),
|
||||
progressbar.OptionShowBytes(true),
|
||||
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
|
||||
progressbar.OptionClearOnFinish(),
|
||||
)
|
||||
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if _, err = io.Copy(h, f); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = io.Copy(h, f); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hash256 = h.Sum(nil)
|
||||
return
|
||||
}
|
||||
|
||||
var imofull = imohash.NewCustom(0, 0)
|
||||
var imopartial = imohash.NewCustom(16*16*8*1024, 128*1024)
|
||||
|
||||
// IMOHashFile returns imohash
|
||||
func IMOHashFile(fname string) (hash []byte, err error) {
|
||||
b, err := imopartial.SumFile(fname)
|
||||
b, err := imohash.SumFile(fname)
|
||||
hash = b[:]
|
||||
return
|
||||
}
|
||||
|
||||
var imofull = imohash.NewCustom(0, 0)
|
||||
|
||||
// IMOHashFileFull returns imohash of full file
|
||||
func IMOHashFileFull(fname string) (hash []byte, err error) {
|
||||
b, err := imofull.SumFile(fname)
|
||||
|
|
@ -204,7 +128,7 @@ func IMOHashFileFull(fname string) (hash []byte, err error) {
|
|||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -212,25 +136,8 @@ func XXHashFile(fname string, doShowProgress bool) (hash256 []byte, err error) {
|
|||
defer f.Close()
|
||||
|
||||
h := xxhash.New()
|
||||
if doShowProgress {
|
||||
stat, _ := f.Stat()
|
||||
fnameShort := path.Base(fname)
|
||||
if len(fnameShort) > 20 {
|
||||
fnameShort = fnameShort[:20] + "..."
|
||||
}
|
||||
bar := progressbar.NewOptions64(stat.Size(),
|
||||
progressbar.OptionSetWriter(os.Stderr),
|
||||
progressbar.OptionShowBytes(true),
|
||||
progressbar.OptionSetDescription(fmt.Sprintf("Hashing %s", fnameShort)),
|
||||
progressbar.OptionClearOnFinish(),
|
||||
)
|
||||
if _, err = io.Copy(io.MultiWriter(h, bar), f); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if _, err = io.Copy(h, f); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = io.Copy(h, f); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hash256 = h.Sum(nil)
|
||||
|
|
@ -246,21 +153,19 @@ func SHA256(s string) string {
|
|||
|
||||
// PublicIP returns public ip address
|
||||
func PublicIP() (ip string, err error) {
|
||||
// ask ipv4.icanhazip.com for the public ip
|
||||
// by making http request
|
||||
// if the request fails, return nothing
|
||||
resp, err := http.Get("http://ipv4.icanhazip.com")
|
||||
resp, err := http.Get("https://canhazip.com")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// read the body of the response
|
||||
// and return the ip address
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(resp.Body)
|
||||
ip = strings.TrimSpace(buf.String())
|
||||
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
bodyBytes, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
ip = strings.TrimSpace(string(bodyBytes))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -268,8 +173,7 @@ func PublicIP() (ip string, err error) {
|
|||
func LocalIP() string {
|
||||
conn, err := net.Dial("udp", "8.8.8.8:80")
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
|
|
@ -282,7 +186,7 @@ func GenerateRandomPin() string {
|
|||
s := ""
|
||||
max := new(big.Int)
|
||||
max.SetInt64(9)
|
||||
for i := 0; i < NbPinNumbers; i++ {
|
||||
for i := 0; i < 4; i++ {
|
||||
v, err := rand.Int(rand.Reader, max)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -295,7 +199,7 @@ func GenerateRandomPin() string {
|
|||
// GetRandomName returns mnemonicoded random name
|
||||
func GetRandomName() string {
|
||||
var result []string
|
||||
bs := make([]byte, NbBytesWords)
|
||||
bs := make([]byte, 4)
|
||||
rand.Read(bs)
|
||||
result = mnemonicode.EncodeWordList(result, bs)
|
||||
return GenerateRandomPin() + "-" + strings.Join(result, "-")
|
||||
|
|
@ -364,6 +268,7 @@ func MissingChunks(fname string, fsize int64, chunkSize int) (chunkRanges []int6
|
|||
}
|
||||
}
|
||||
chunkRanges = append(chunkRanges, int64(curCount+1))
|
||||
chunks = chunkRanges
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -452,7 +357,7 @@ func init() {
|
|||
}
|
||||
|
||||
func IsLocalIP(ipaddress string) bool {
|
||||
if strings.Contains(ipaddress, "127.0.0.1") {
|
||||
if strings.Contains(ipaddress, "localhost") {
|
||||
return true
|
||||
}
|
||||
host, _, _ := net.SplitHostPort(ipaddress)
|
||||
|
|
@ -469,13 +374,13 @@ func IsLocalIP(ipaddress string) bool {
|
|||
}
|
||||
|
||||
func ZipDirectory(destination string, source string) (err error) {
|
||||
if _, err = os.Stat(destination); err == nil {
|
||||
log.Errorf("%s file already exists!\n", destination)
|
||||
if _, err := os.Stat(destination); err == nil {
|
||||
log.Fatalf("%s file already exists!\n", destination)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Zipping %s to %s\n", source, destination)
|
||||
file, err := os.Create(destination)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer file.Close()
|
||||
writer := zip.NewWriter(file)
|
||||
|
|
@ -486,39 +391,39 @@ func ZipDirectory(destination string, source string) (err error) {
|
|||
defer writer.Close()
|
||||
err = filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
if info.Mode().IsRegular() {
|
||||
f1, err := os.Open(path)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer f1.Close()
|
||||
zipPath := strings.ReplaceAll(path, source, strings.TrimSuffix(destination, ".zip"))
|
||||
zipPath = filepath.ToSlash(zipPath)
|
||||
w1, err := writer.Create(zipPath)
|
||||
zip_path := strings.ReplaceAll(path, source, strings.TrimSuffix(destination, ".zip"))
|
||||
w1, err := writer.Create(zip_path)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
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, "\rAdding %s", zipPath)
|
||||
fmt.Fprintf(os.Stderr, "\rAdding %s", zip_path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
func UnzipDirectory(destination string, source string) error {
|
||||
|
||||
archive, err := zip.OpenReader(source)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer archive.Close()
|
||||
|
||||
|
|
@ -526,43 +431,27 @@ func UnzipDirectory(destination string, source string) error {
|
|||
filePath := filepath.Join(destination, f.Name)
|
||||
fmt.Fprintf(os.Stderr, "\r\033[2K")
|
||||
fmt.Fprintf(os.Stderr, "\rUnzipping file %s", filePath)
|
||||
// Issue #593 conceal path traversal vulnerability
|
||||
// make sure the filepath does not have ".."
|
||||
filePath = filepath.Clean(filePath)
|
||||
if strings.Contains(filePath, "..") {
|
||||
log.Errorf("Invalid file path %s\n", filePath)
|
||||
}
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(filePath, os.ModePerm)
|
||||
continue
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
||||
log.Error(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
|
||||
}
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
fileInArchive, err := f.Open()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
if _, err := io.Copy(dstFile, fileInArchive); err != nil {
|
||||
log.Error(err)
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
dstFile.Close()
|
||||
|
|
@ -571,67 +460,3 @@ func UnzipDirectory(destination string, source string) error {
|
|||
fmt.Fprintf(os.Stderr, "\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidFileName checks if a filename is valid
|
||||
// by making sure it has no invisible characters
|
||||
func ValidFileName(fname string) (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"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
|
@ -18,14 +17,14 @@ const TCP_BUFFER_SIZE = 1024 * 64
|
|||
var bigFileSize = 75000000
|
||||
|
||||
func bigFile() {
|
||||
os.WriteFile("bigfile.test", bytes.Repeat([]byte("z"), bigFileSize), 0o666)
|
||||
os.WriteFile("bigfile.test", bytes.Repeat([]byte("z"), bigFileSize), 0666)
|
||||
}
|
||||
|
||||
func BenchmarkMD5(b *testing.B) {
|
||||
bigFile()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
MD5HashFile("bigfile.test", false)
|
||||
MD5HashFile("bigfile.test")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +32,7 @@ func BenchmarkXXHash(b *testing.B) {
|
|||
bigFile()
|
||||
b.ResetTimer()
|
||||
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) {
|
||||
bigFile()
|
||||
b.ResetTimer()
|
||||
|
|
@ -87,20 +78,10 @@ func TestExists(t *testing.T) {
|
|||
func TestMD5HashFile(t *testing.T) {
|
||||
bigFile()
|
||||
defer os.Remove("bigfile.test")
|
||||
b, err := MD5HashFile("bigfile.test", false)
|
||||
b, err := MD5HashFile("bigfile.test")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "8304ff018e02baad0e3555bade29a405", fmt.Sprintf("%x", b))
|
||||
_, err = MD5HashFile("bigfile.test.nofile", false)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestHighwayHashFile(t *testing.T) {
|
||||
bigFile()
|
||||
defer os.Remove("bigfile.test")
|
||||
b, err := HighwayHashFile("bigfile.test", false)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "3c32999529323ed66a67aeac5720c7bf1301dcc5dca87d8d46595e85ff990329", fmt.Sprintf("%x", b))
|
||||
_, err = HighwayHashFile("bigfile.test.nofile", false)
|
||||
_, err = MD5HashFile("bigfile.test.nofile")
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
|
|
@ -109,16 +90,16 @@ func TestIMOHashFile(t *testing.T) {
|
|||
defer os.Remove("bigfile.test")
|
||||
b, err := IMOHashFile("bigfile.test")
|
||||
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) {
|
||||
bigFile()
|
||||
defer os.Remove("bigfile.test")
|
||||
b, err := XXHashFile("bigfile.test", false)
|
||||
b, err := XXHashFile("bigfile.test")
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "4918740eb5ccb6f7", fmt.Sprintf("%x", b))
|
||||
_, err = XXHashFile("nofile", false)
|
||||
_, err = XXHashFile("nofile")
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
|
|
@ -138,9 +119,9 @@ func TestMissingChunks(t *testing.T) {
|
|||
rand.Seed(1)
|
||||
bigBuff := make([]byte, fileSize)
|
||||
rand.Read(bigBuff)
|
||||
os.WriteFile("missing.test", bigBuff, 0o644)
|
||||
os.WriteFile("missing.test", bigBuff, 0644)
|
||||
empty := make([]byte, chunkSize)
|
||||
f, err := os.OpenFile("missing.test", os.O_RDWR, 0o644)
|
||||
f, err := os.OpenFile("missing.test", os.O_RDWR, 0644)
|
||||
assert.Nil(t, err)
|
||||
for block := 0; block < fileSize/chunkSize; block++ {
|
||||
if block == 0 || block == 4 || block == 5 || block >= 7 {
|
||||
|
|
@ -197,10 +178,10 @@ func TestHashFile(t *testing.T) {
|
|||
|
||||
defer os.Remove(tmpfile.Name()) // clean up
|
||||
|
||||
if _, err = tmpfile.Write(content); err != nil {
|
||||
if _, err := tmpfile.Write(content); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err = tmpfile.Close(); err != nil {
|
||||
if err := tmpfile.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
hashed, err := HashFile(tmpfile.Name(), "xxhash")
|
||||
|
|
@ -227,41 +208,11 @@ func TestGetRandomName(t *testing.T) {
|
|||
assert.NotEmpty(t, name)
|
||||
}
|
||||
|
||||
func intSliceSame(a, b []int) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestFindOpenPorts(t *testing.T) {
|
||||
openPorts := FindOpenPorts("127.0.0.1", 9009, 4)
|
||||
if !intSliceSame(openPorts, []int{9009, 9010, 9011, 9012}) && !intSliceSame(openPorts, []int{9014, 9015, 9016, 9017}) {
|
||||
t.Errorf("openPorts: %v", openPorts)
|
||||
|
||||
}
|
||||
openPorts := FindOpenPorts("localhost", 9009, 4)
|
||||
assert.Equal(t, []int{9009, 9010, 9011, 9012}, openPorts)
|
||||
}
|
||||
|
||||
func TestIsLocalIP(t *testing.T) {
|
||||
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