Compare commits
157 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
788dfa203f | ||
|
440ccf3a57 | ||
|
224f8dca42 | ||
|
d16a6cc25e | ||
|
49a083d8a2 | ||
|
f38eb6fb77 | ||
|
8f5a0a80f3 | ||
|
a895846bbc | ||
|
3990c3c5b7 | ||
|
3ea4ffd0e3 | ||
|
88003018e6 | ||
|
9baefbc4bf | ||
|
e9148e0c20 | ||
|
2ecedb93c6 | ||
|
1ff9ccd01e | ||
|
ca17555c22 | ||
|
a7a3e685fe | ||
|
94f94f27ff | ||
|
69d979ca48 | ||
|
d9198e78db | ||
|
811679f8fb | ||
|
ce0c9b8915 | ||
|
c93c585566 | ||
|
0eb3ba9ff8 | ||
|
1594f95abf | ||
|
8f6e44b212 | ||
|
2e2c07c3a0 | ||
|
9df18fdc69 | ||
|
49c6d7ee4f | ||
|
fdfd453222 | ||
|
b5ffdb5095 | ||
|
0512452111 | ||
|
16e94447f7 | ||
|
941ec1fe0f | ||
|
6bd3e97186 | ||
|
31ef712847 | ||
|
4daca97f89 | ||
|
69519d8fa4 | ||
|
a90d29700d | ||
|
f9700ee237 | ||
|
3ed153904d | ||
|
b36711c1ea | ||
|
27f84e719a | ||
|
0b075554ff | ||
|
eaf048690a | ||
|
4dbc2a8085 | ||
|
644c3a1d23 | ||
|
ccef887edf | ||
|
32621f7dd3 | ||
|
7ea65c5a24 | ||
|
27bf261844 | ||
|
7522cf5f31 | ||
|
ba21621d66 | ||
|
7cf688e86e | ||
|
1abc7cfb0e | ||
|
be6dea2546 | ||
|
d554eb8e2d | ||
|
fe9e699255 | ||
|
d3b6fd5e90 | ||
|
322310d47f | ||
|
76fd83b599 | ||
|
d3381a2293 | ||
|
6ac6c8fa99 | ||
|
2721ece759 | ||
|
e53d599e09 | ||
|
bfb34634de | ||
|
614a7fd23d | ||
|
fb8f0e781b | ||
|
06d87eac8e | ||
|
580cd8d978 | ||
|
111f1794fb | ||
|
b372dc97b5 | ||
|
ae00f8ceaa | ||
|
ec9db7a42e | ||
|
bcf40c15a2 | ||
|
fe1cde6614 | ||
|
e182376100 | ||
|
4a2fce4344 | ||
|
ffb2cf0011 | ||
|
085e9f8414 | ||
|
a4bf102d29 | ||
|
c8497fb27d | ||
|
68212d100e | ||
|
18f4b42cf1 | ||
|
92055f1b3c | ||
|
9430e53689 | ||
|
a26b32dd86 | ||
|
0a6b5817a9 | ||
|
5e7e3a1b39 | ||
|
42adceb4c6 | ||
|
f909ad3ce2 | ||
|
d830bf1afc | ||
|
f366e8217e | ||
|
8a5c737140 | ||
|
b920eb842a | ||
|
45e0967a37 | ||
|
28614c991d | ||
|
ef28bcb28f | ||
|
2dd23bff3c | ||
|
663c59e754 | ||
|
c89b7f56c2 | ||
|
8bb5094ccc | ||
|
b7deec505b | ||
|
c62e5757ef | ||
|
38d643e12b | ||
|
0411db0443 | ||
|
3b1b5b890a | ||
|
fb3d410004 | ||
|
924275e45b | ||
|
fdca501681 | ||
|
38996c9c7f | ||
|
9f9e1b66b2 | ||
|
b3f2319cba | ||
|
867471aa9c | ||
|
96fb3cbe61 | ||
|
800dd6658e | ||
|
2e33f7c716 | ||
|
5fab83bde8 | ||
|
dcaf572f3d | ||
|
ce4e015641 | ||
|
9c15248adc | ||
|
d8e1248949 | ||
|
7dc3982c77 | ||
|
82617a25c1 | ||
|
fcbddcee17 | ||
|
8b92f5bac4 | ||
|
8aa835f21f | ||
|
9297c253aa | ||
|
b22a410a78 | ||
|
229482fa3d | ||
|
f22bfbf804 | ||
|
8ecc94ed7c | ||
|
0ee2dfd7e1 | ||
|
b90bd685e7 | ||
|
73e2bca999 | ||
|
d09f4fdd81 | ||
|
356412c838 | ||
|
6b249d21c4 | ||
|
c0d5d99e5d | ||
|
9e27485bbb | ||
|
b8ca25fb9b | ||
|
bef766f605 | ||
|
c2a152c622 | ||
|
c403f9a2f1 | ||
|
8d196039ba | ||
|
11ad244584 | ||
|
060dbdf152 | ||
|
2127b4f1e4 | ||
|
6eabb248da | ||
|
5bb0e84fa5 | ||
|
1e815d382c | ||
|
cf00af36f2 | ||
|
79c5130066 | ||
|
c1691c58dc | ||
|
d5e07fe2f4 | ||
|
874268d80e | ||
|
59014f2110 |
@@ -6,7 +6,6 @@ bin
|
||||
*.pyc
|
||||
*.egg-info
|
||||
.vagrant
|
||||
.git
|
||||
.tmp
|
||||
bower_components
|
||||
node_modules
|
||||
|
33
.github/build/friendly-filenames.json
vendored
Normal file
33
.github/build/friendly-filenames.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"android-arm64": { "friendlyName": "android-arm64-v8a" },
|
||||
"darwin-amd64": { "friendlyName": "darwin-amd64" },
|
||||
"darwin-arm64": { "friendlyName": "darwin-arm64" },
|
||||
"dragonfly-amd64": { "friendlyName": "dragonfly-amd64" },
|
||||
"freebsd-386": { "friendlyName": "freebsd-386" },
|
||||
"freebsd-amd64": { "friendlyName": "freebsd-amd64" },
|
||||
"freebsd-arm64": { "friendlyName": "freebsd-arm64-v8a" },
|
||||
"freebsd-arm7": { "friendlyName": "freebsd-arm32-v7a" },
|
||||
"linux-386": { "friendlyName": "linux-386" },
|
||||
"linux-amd64": { "friendlyName": "linux-amd64" },
|
||||
"linux-arm5": { "friendlyName": "linux-arm32-v5" },
|
||||
"linux-arm64": { "friendlyName": "linux-arm64-v8a" },
|
||||
"linux-arm6": { "friendlyName": "linux-arm32-v6" },
|
||||
"linux-arm7": { "friendlyName": "linux-armv7" },
|
||||
"linux-mips64le": { "friendlyName": "linux-mips64le" },
|
||||
"linux-mips64": { "friendlyName": "linux-mips64" },
|
||||
"linux-mipslesoftfloat": { "friendlyName": "linux-mips32le-softfloat" },
|
||||
"linux-mipsle": { "friendlyName": "linux-mips32le" },
|
||||
"linux-mipssoftfloat": { "friendlyName": "linux-mips32-softfloat" },
|
||||
"linux-mips": { "friendlyName": "linux-mips32" },
|
||||
"linux-ppc64le": { "friendlyName": "linux-ppc64le" },
|
||||
"linux-ppc64": { "friendlyName": "linux-ppc64" },
|
||||
"linux-riscv64": { "friendlyName": "linux-riscv64" },
|
||||
"linux-s390x": { "friendlyName": "linux-s390x" },
|
||||
"openbsd-386": { "friendlyName": "openbsd-386" },
|
||||
"openbsd-amd64": { "friendlyName": "openbsd-amd64" },
|
||||
"openbsd-arm64": { "friendlyName": "openbsd-arm64-v8a" },
|
||||
"openbsd-arm7": { "friendlyName": "openbsd-arm32-v7a" },
|
||||
"windows-386": { "friendlyName": "windows-386" },
|
||||
"windows-amd64": { "friendlyName": "windows-amd64" },
|
||||
"windows-arm7": { "friendlyName": "windows-arm32-v7a" }
|
||||
}
|
89
.github/workflows/build-docker-images.yml
vendored
Normal file
89
.github/workflows/build-docker-images.yml
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
name: deploy multi-architecture Docker images for transfer.sh with buildx
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *' # everyday at midnight UTC
|
||||
pull_request:
|
||||
branches: master
|
||||
push:
|
||||
branches: master
|
||||
tags:
|
||||
- v*
|
||||
|
||||
jobs:
|
||||
buildx:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
-
|
||||
name: Prepare
|
||||
id: prepare
|
||||
run: |
|
||||
DOCKER_IMAGE=dutchcoders/transfer.sh
|
||||
DOCKER_PLATFORMS=linux/amd64,linux/arm/v7,linux/arm64,linux/386
|
||||
VERSION=edge
|
||||
|
||||
if [[ $GITHUB_REF == refs/tags/* ]]; then
|
||||
VERSION=v${GITHUB_REF#refs/tags/v}
|
||||
fi
|
||||
|
||||
if [ "${{ github.event_name }}" = "schedule" ]; then
|
||||
VERSION=nightly
|
||||
fi
|
||||
|
||||
TAGS="--tag ${DOCKER_IMAGE}:${VERSION}"
|
||||
|
||||
if [ $VERSION = edge -o $VERSION = nightly ]; then
|
||||
TAGS="$TAGS --tag ${DOCKER_IMAGE}:latest"
|
||||
fi
|
||||
|
||||
echo ::set-output name=docker_image::${DOCKER_IMAGE}
|
||||
echo ::set-output name=version::${VERSION}
|
||||
echo ::set-output name=buildx_args::--platform ${DOCKER_PLATFORMS} \
|
||||
--build-arg VERSION=${VERSION} \
|
||||
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
|
||||
--build-arg VCS_REF=${GITHUB_SHA::8} \
|
||||
${TAGS} .
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
with:
|
||||
platforms: all
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
with:
|
||||
version: latest
|
||||
-
|
||||
name: Available platforms
|
||||
run: echo ${{ steps.buildx.outputs.platforms }}
|
||||
-
|
||||
name: Docker Buildx (build)
|
||||
run: |
|
||||
docker buildx build --no-cache --pull --output "type=image,push=false" ${{ steps.prepare.outputs.buildx_args }}
|
||||
-
|
||||
name: Docker Login
|
||||
if: success() && github.event_name != 'pull_request'
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
run: |
|
||||
echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin
|
||||
-
|
||||
name: Docker Buildx (push)
|
||||
if: success() && github.event_name != 'pull_request'
|
||||
run: |
|
||||
docker buildx build --output "type=image,push=true" ${{ steps.prepare.outputs.buildx_args }}
|
||||
-
|
||||
name: Docker Check Manifest
|
||||
if: always() && github.event_name != 'pull_request'
|
||||
run: |
|
||||
docker run --rm mplatform/mquery ${{ steps.prepare.outputs.docker_image }}:${{ steps.prepare.outputs.version }}
|
||||
-
|
||||
name: Clear
|
||||
if: always() && github.event_name != 'pull_request'
|
||||
run: |
|
||||
rm -f ${HOME}/.docker/config.json
|
179
.github/workflows/release.yml
vendored
Normal file
179
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
name: Build and Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [published]
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- "**/*.go"
|
||||
- "go.mod"
|
||||
- "go.sum"
|
||||
- ".github/workflows/*.yml"
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
# Include amd64 on all platforms.
|
||||
goos: [windows, freebsd, openbsd, linux, dragonfly, darwin]
|
||||
goarch: [amd64, 386]
|
||||
exclude:
|
||||
# Exclude i386 on darwin and dragonfly.
|
||||
- goarch: 386
|
||||
goos: dragonfly
|
||||
- goarch: 386
|
||||
goos: darwin
|
||||
include:
|
||||
# BEIGIN MacOS ARM64
|
||||
- goos: darwin
|
||||
goarch: arm64
|
||||
# END MacOS ARM64
|
||||
# BEGIN Linux ARM 5 6 7
|
||||
- goos: linux
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
- goos: linux
|
||||
goarch: arm
|
||||
goarm: 6
|
||||
- goos: linux
|
||||
goarch: arm
|
||||
goarm: 5
|
||||
# END Linux ARM 5 6 7
|
||||
# BEGIN Android ARM 8
|
||||
- goos: android
|
||||
goarch: arm64
|
||||
# END Android ARM 8
|
||||
# Windows ARM 7
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
# BEGIN Other architectures
|
||||
# BEGIN riscv64 & ARM64
|
||||
- goos: linux
|
||||
goarch: arm64
|
||||
- goos: linux
|
||||
goarch: riscv64
|
||||
# END riscv64 & ARM64
|
||||
# BEGIN MIPS
|
||||
- goos: linux
|
||||
goarch: mips64
|
||||
- goos: linux
|
||||
goarch: mips64le
|
||||
- goos: linux
|
||||
goarch: mipsle
|
||||
- goos: linux
|
||||
goarch: mips
|
||||
# END MIPS
|
||||
# BEGIN PPC
|
||||
- goos: linux
|
||||
goarch: ppc64
|
||||
- goos: linux
|
||||
goarch: ppc64le
|
||||
# END PPC
|
||||
# BEGIN FreeBSD ARM
|
||||
- goos: freebsd
|
||||
goarch: arm64
|
||||
- goos: freebsd
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
# END FreeBSD ARM
|
||||
# BEGIN S390X
|
||||
- goos: linux
|
||||
goarch: s390x
|
||||
# END S390X
|
||||
# END Other architectures
|
||||
# BEGIN OPENBSD ARM
|
||||
- goos: openbsd
|
||||
goarch: arm64
|
||||
- goos: openbsd
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
# END OPENBSD ARM
|
||||
fail-fast: false
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GOOS: ${{ matrix.goos }}
|
||||
GOARCH: ${{ matrix.goarch }}
|
||||
GOARM: ${{ matrix.goarm }}
|
||||
CGO_ENABLED: 0
|
||||
steps:
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Show workflow information
|
||||
id: get_filename
|
||||
run: |
|
||||
export _NAME=$(jq ".[\"$GOOS-$GOARCH$GOARM$GOMIPS\"].friendlyName" -r < .github/build/friendly-filenames.json)
|
||||
echo "GOOS: $GOOS, GOARCH: $GOARCH, GOARM: $GOARM, GOMIPS: $GOMIPS, RELEASE_NAME: $_NAME"
|
||||
echo "::set-output name=ASSET_NAME::$_NAME"
|
||||
echo "::set-output name=GIT_TAG::${GITHUB_REF##*/}"
|
||||
echo "ASSET_NAME=$_NAME" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.16
|
||||
|
||||
- name: Get project dependencies
|
||||
run: go mod download
|
||||
|
||||
- name: Build Transfersh
|
||||
run: |
|
||||
mkdir -p build_assets
|
||||
go build -tags netgo -ldflags "-X github.com/dutchcoders/transfer.sh/cmd.Version=${GITHUB_REF##*/} -a -s -w -extldflags '-static'" -o build_assets/transfersh-${GITHUB_REF##*/}-${ASSET_NAME}
|
||||
|
||||
- name: Build Mips softfloat Transfersh
|
||||
if: matrix.goarch == 'mips' || matrix.goarch == 'mipsle'
|
||||
run: |
|
||||
GOMIPS=softfloat go build -tags netgo -ldflags "-X github.com/dutchcoders/transfer.sh/cmd.Version=${GITHUB_REF##*/} -a -s -w -extldflags '-static'" -o build_assets/transfersh-softfloat-${GITHUB_REF##*/}-${ASSET_NAME}
|
||||
|
||||
- name: Rename Windows Transfersh
|
||||
if: matrix.goos == 'windows'
|
||||
run: |
|
||||
cd ./build_assets || exit 1
|
||||
mv transfersh-${GITHUB_REF##*/}-${ASSET_NAME} transfersh-${GITHUB_REF##*/}-${ASSET_NAME}.exe
|
||||
|
||||
- name: Prepare to release
|
||||
run: |
|
||||
cp ${GITHUB_WORKSPACE}/README.md ./build_assets/README.md
|
||||
cp ${GITHUB_WORKSPACE}/LICENSE ./build_assets/LICENSE
|
||||
|
||||
- name: Create Gzip archive
|
||||
shell: bash
|
||||
run: |
|
||||
pushd build_assets || exit 1
|
||||
touch -mt $(date +%Y01010000) *
|
||||
tar zcvf transfersh-${GITHUB_REF##*/}-${ASSET_NAME}.tar.gz *
|
||||
mv transfersh-${GITHUB_REF##*/}-${ASSET_NAME}.tar.gz ../
|
||||
FILE=`find . -name "transfersh-${GITHUB_REF##*/}-${ASSET_NAME}*"`
|
||||
DGST=$FILE.sha256sum
|
||||
echo `sha256sum $FILE` > $DGST
|
||||
popd || exit 1
|
||||
FILE=./transfersh-${GITHUB_REF##*/}-${ASSET_NAME}.tar.gz
|
||||
DGST=$FILE.sha256sum
|
||||
echo `sha256sum $FILE` > $DGST
|
||||
|
||||
- name: Change the name
|
||||
run: |
|
||||
mv build_assets transfersh-${GITHUB_REF##*/}-${ASSET_NAME}
|
||||
|
||||
- name: Upload files to Artifacts
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: transfersh-${{ steps.get_filename.outputs.GIT_TAG }}-${{ steps.get_filename.outputs.ASSET_NAME }}
|
||||
path: |
|
||||
./transfersh-${{ steps.get_filename.outputs.GIT_TAG }}-${{ steps.get_filename.outputs.ASSET_NAME }}/*
|
||||
|
||||
- name: Upload binaries to release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
./transfersh-${{ steps.get_filename.outputs.GIT_TAG }}-${{ steps.get_filename.outputs.ASSET_NAME }}.tar.gz*
|
||||
./transfersh-${{ steps.get_filename.outputs.GIT_TAG }}-${{ steps.get_filename.outputs.ASSET_NAME }}/transfersh-${{ steps.get_filename.outputs.GIT_TAG }}-${{ steps.get_filename.outputs.ASSET_NAME }}*
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
30
.github/workflows/test.yml
vendored
Normal file
30
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: test
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "*"
|
||||
push:
|
||||
branches:
|
||||
- "*"
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go_version:
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
- 1.16.x
|
||||
name: Test with ${{ matrix.go_version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go_version }}
|
||||
- name: Vet and test
|
||||
run: |
|
||||
go version
|
||||
go vet ./...
|
||||
go test ./...
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -20,3 +20,5 @@ transfersh-server/run.sh
|
||||
.elasticbeanstalk/*
|
||||
!.elasticbeanstalk/*.cfg.yml
|
||||
!.elasticbeanstalk/*.global.yml
|
||||
|
||||
!.github/build/
|
||||
|
57
.travis.yml
57
.travis.yml
@@ -1,57 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
go:
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- tip
|
||||
|
||||
install:
|
||||
- echo "This is an override of the default install deps step in travis."
|
||||
|
||||
script:
|
||||
- go get -t -u -v ./...
|
||||
- go build -v .
|
||||
- go vet ./...
|
||||
- go test ./...
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: Fuzz regression
|
||||
go: 1.12.x
|
||||
dist: bionic
|
||||
script: ./fuzzit.sh local-regression
|
||||
- stage: Fuzz
|
||||
if: branch = fuzz AND type IN (push)
|
||||
go: 1.12.x
|
||||
dist: bionic
|
||||
script: ./fuzzit.sh fuzzing
|
||||
|
||||
before_deploy:
|
||||
- mkdir -p release
|
||||
- "GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags -a -tags netgo -ldflags '-s -w -extldflags -static' -o release/transfersh-$TRAVIS_TAG-linux-amd64"
|
||||
- "GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=0 go build -ldflags -a -tags netgo -ldflags '-s -w -extldflags -static' -o release/transfersh-$TRAVIS_TAG-linux-armv7"
|
||||
- "GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags -a -tags netgo -ldflags '-s -w -extldflags -static' -o release/transfersh-$TRAVIS_TAG-darwin-amd64"
|
||||
- "GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags -a -tags netgo -ldflags '-s -w -extldflags -static' -o release/transfersh-$TRAVIS_TAG-win-amd64.exe"
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: cOuMGyvrl/9GX3TZFL+Vq++2Bv5Hlb3VfXSYONfeAj+1AXI3Y+tPruy/XnWpa1MUxkvFuIhea3sUAiKfwhHip9csCmMUhDJtaTU9apsxRkyF/OFrWb7/FlbnqYuAwnp91ImvtSlnubg2VHTjhBA6ycNQF7WZcJEMVMsAtC/nSY4=
|
||||
file:
|
||||
- "release/transfersh-$TRAVIS_TAG-linux-amd64"
|
||||
- "release/transfersh-$TRAVIS_TAG-linux-armv7"
|
||||
- "release/transfersh-$TRAVIS_TAG-darwin-amd64"
|
||||
- "release/transfersh-$TRAVIS_TAG-win-amd64.exe"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
go: 1.12.x
|
||||
overwrite: true
|
24
CODE_OF_CONDUCT.md
Normal file
24
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
# Contributor Code of Conduct
|
||||
|
||||
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
||||
|
||||
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery
|
||||
* Personal attacks
|
||||
* Trolling or insulting/derogatory comments
|
||||
* Public or private harassment
|
||||
* Publishing other's private information, such as physical or electronic addresses, without explicit permission
|
||||
* Other unethical or unprofessional conduct
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
||||
|
||||
This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.2.0, available at https://www.contributor-covenant.org/version/1/2/0/code-of-conduct.html
|
||||
|
@@ -1,5 +1,5 @@
|
||||
# Default to Go 1.12
|
||||
ARG GO_VERSION=1.12
|
||||
# Default to Go 1.16
|
||||
ARG GO_VERSION=1.16
|
||||
FROM golang:${GO_VERSION}-alpine as build
|
||||
|
||||
# Necessary to run 'go get' and to compile the linked binary
|
||||
@@ -12,7 +12,7 @@ WORKDIR /go/src/github.com/dutchcoders/transfer.sh
|
||||
ENV GO111MODULE=on
|
||||
|
||||
# build & install server
|
||||
RUN go get -u ./... && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags -a -tags netgo -ldflags '-w -extldflags "-static"' -o /go/bin/transfersh github.com/dutchcoders/transfer.sh
|
||||
RUN CGO_ENABLED=0 go build -tags netgo -ldflags "-X github.com/dutchcoders/transfer.sh/cmd.Version=$(git describe --tags) -a -s -w -extldflags '-static'" -o /go/bin/transfersh
|
||||
|
||||
FROM scratch AS final
|
||||
LABEL maintainer="Andrea Spacca <andrea.spacca@gmail.com>"
|
||||
|
2
LICENSE
2
LICENSE
@@ -1,6 +1,8 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2018 DutchCoders [https://github.com/dutchcoders/]
|
||||
Copyright (c) 2018-2020 Andrea Spacca.
|
||||
Copyright (c) 2020- Andrea Spacca and Stefan Benten.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
139
README.md
139
README.md
@@ -1,13 +1,12 @@
|
||||
# transfer.sh [](https://gitter.im/dutchcoders/transfer.sh?utm_source=badge&utm_medium=badge&utm_campaign=&utm_campaign=pr-badge&utm_content=badge) [](https://goreportcard.com/report/github.com/dutchcoders/transfer.sh) [](https://hub.docker.com/r/dutchcoders/transfer.sh/) [](https://travis-ci.org/dutchcoders/transfer.sh) [](https://app.fuzzit.dev/orgs/transfer.sh/dashboard)
|
||||
# transfer.sh [](https://gitter.im/dutchcoders/transfer.sh?utm_source=badge&utm_medium=badge&utm_campaign=&utm_campaign=pr-badge&utm_content=badge) [](https://goreportcard.com/report/github.com/dutchcoders/transfer.sh) [](https://hub.docker.com/r/dutchcoders/transfer.sh/) [](https://github.com/dutchcoders/transfer.sh/actions/workflows/test.yml?query=branch%3Amaster)
|
||||
|
||||
Easy and fast file sharing from the command-line. This code contains the server with everything you need to create your own instance.
|
||||
|
||||
Transfer.sh currently supports the s3 (Amazon S3), gdrive (Google Drive) providers, and local file system (local).
|
||||
Transfer.sh currently supports the s3 (Amazon S3), gdrive (Google Drive), storj (Storj) providers, and local file system (local).
|
||||
|
||||
## Disclaimer
|
||||
This project repository has no relation with the service at https://transfer.sh that's managed by https://storj.io.
|
||||
So far we cannot address any issue related to the service at https://transfer.sh.
|
||||
|
||||
The service at transfersh.com is of unknown origin and reported as cloud malware.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -76,40 +75,50 @@ https://transfer.sh/1lDau/test.txt --> https://transfer.sh/inline/1lDau/test.txt
|
||||
|
||||
Parameter | Description | Value | Env
|
||||
--- | --- | --- | ---
|
||||
listener | port to use for http (:80) | |
|
||||
profile-listener | port to use for profiler (:6060)| |
|
||||
force-https | redirect to https | false |
|
||||
tls-listener | port to use for https (:443) | |
|
||||
tls-listener-only | flag to enable tls listener only | |
|
||||
tls-cert-file | path to tls certificate | |
|
||||
tls-private-key | path to tls private key | |
|
||||
http-auth-user | user for basic http auth on upload | |
|
||||
http-auth-pass | pass for basic http auth on upload | |
|
||||
ip-whitelist | comma separated list of ips allowed to connect to the service | |
|
||||
ip-blacklist | comma separated list of ips not allowed to connect to the service | |
|
||||
temp-path | path to temp folder | system temp |
|
||||
web-path | path to static web files (for development or custom front end) | |
|
||||
proxy-path | path prefix when service is run behind a proxy | |
|
||||
ga-key | google analytics key for the front end | |
|
||||
uservoice-key | user voice key for the front end | |
|
||||
provider | which storage provider to use | (s3, gdrive or local) |
|
||||
aws-access-key | aws access key | | AWS_ACCESS_KEY
|
||||
aws-secret-key | aws access key | | AWS_SECRET_KEY
|
||||
bucket | aws bucket | | BUCKET
|
||||
s3-endpoint | Custom S3 endpoint. | |
|
||||
s3-region | region of the s3 bucket | eu-west-1 | S3_REGION
|
||||
s3-no-multipart | disables s3 multipart upload | false | |
|
||||
s3-path-style | Forces path style URLs, required for Minio. | false | |
|
||||
basedir | path storage for local/gdrive provider| |
|
||||
gdrive-client-json-filepath | path to oauth client json config for gdrive provider| |
|
||||
gdrive-local-config-path | path to store local transfer.sh config cache for gdrive provider| |
|
||||
gdrive-chunk-size | chunk size for gdrive upload in megabytes, must be lower than available memory (8 MB) | |
|
||||
lets-encrypt-hosts | hosts to use for lets encrypt certificates (comma seperated) | |
|
||||
log | path to log file| |
|
||||
listener | port to use for http (:80) | | LISTENER |
|
||||
profile-listener | port to use for profiler (:6060) | | PROFILE_LISTENER |
|
||||
force-https | redirect to https | false | FORCE_HTTPS
|
||||
tls-listener | port to use for https (:443) | | TLS_LISTENER |
|
||||
tls-listener-only | flag to enable tls listener only | | TLS_LISTENER_ONLY |
|
||||
tls-cert-file | path to tls certificate | | TLS_CERT_FILE |
|
||||
tls-private-key | path to tls private key | | TLS_PRIVATE_KEY |
|
||||
http-auth-user | user for basic http auth on upload | | HTTP_AUTH_USER |
|
||||
http-auth-pass | pass for basic http auth on upload | | HTTP_AUTH_PASS |
|
||||
ip-whitelist | comma separated list of ips allowed to connect to the service | | IP_WHITELIST |
|
||||
ip-blacklist | comma separated list of ips not allowed to connect to the service | | IP_BLACKLIST |
|
||||
temp-path | path to temp folder | system temp | TEMP_PATH |
|
||||
web-path | path to static web files (for development or custom front end) | | WEB_PATH |
|
||||
proxy-path | path prefix when service is run behind a proxy | | PROXY_PATH |
|
||||
proxy-port | port of the proxy when the service is run behind a proxy | | PROXY_PORT |
|
||||
ga-key | google analytics key for the front end | | GA_KEY |
|
||||
provider | which storage provider to use | (s3, storj, gdrive or local) |
|
||||
uservoice-key | user voice key for the front end | | USERVOICE_KEY |
|
||||
aws-access-key | aws access key | | AWS_ACCESS_KEY |
|
||||
aws-secret-key | aws access key | | AWS_SECRET_KEY |
|
||||
bucket | aws bucket | | BUCKET |
|
||||
s3-endpoint | Custom S3 endpoint. | | S3_ENDPOINT |
|
||||
s3-region | region of the s3 bucket | eu-west-1 | S3_REGION |
|
||||
s3-no-multipart | disables s3 multipart upload | false | S3_NO_MULTIPART |
|
||||
s3-path-style | Forces path style URLs, required for Minio. | false | S3_PATH_STYLE |
|
||||
storj-access | Access for the project | | STORJ_ACCESS |
|
||||
storj-bucket | Bucket to use within the project | | STORJ_BUCKET |
|
||||
basedir | path storage for local/gdrive provider | | BASEDIR |
|
||||
gdrive-client-json-filepath | path to oauth client json config for gdrive provider | | GDRIVE_CLIENT_JSON_FILEPATH |
|
||||
gdrive-local-config-path | path to store local transfer.sh config cache for gdrive provider| | GDRIVE_LOCAL_CONFIG_PATH |
|
||||
gdrive-chunk-size | chunk size for gdrive upload in megabytes, must be lower than available memory (8 MB) | | GDRIVE_CHUNK_SIZE |
|
||||
lets-encrypt-hosts | hosts to use for lets encrypt certificates (comma seperated) | | HOSTS |
|
||||
log | path to log file| | LOG |
|
||||
cors-domains | comma separated list of domains for CORS, setting it enable CORS | | CORS_DOMAINS |
|
||||
clamav-host | host for clamav feature | | CLAMAV_HOST |
|
||||
rate-limit | request per minute | | RATE_LIMIT |
|
||||
max-upload-size | max upload size in kilobytes | | MAX_UPLOAD_SIZE |
|
||||
purge-days | number of days after the uploads are purged automatically | | PURGE_DAYS |
|
||||
purge-interval | interval in hours to run the automatic purge for (not applicable to S3 and Storj) | | PURGE_INTERVAL |
|
||||
random-token-length | length of the random token for the upload path (double the size for delete path) | 6 | RANDOM_TOKEN_LENGTH |
|
||||
|
||||
If you want to use TLS using lets encrypt certificates, set lets-encrypt-hosts to your domain, set tls-listener to :443 and enable force-https.
|
||||
|
||||
If you want to use TLS using your own certificates, set tls-listener to :443, force-https, tls-cert=file and tls-private-key.
|
||||
If you want to use TLS using your own certificates, set tls-listener to :443, force-https, tls-cert-file and tls-private-key.
|
||||
|
||||
## Development
|
||||
|
||||
@@ -121,13 +130,10 @@ go run main.go --provider=local --listener :8080 --temp-path=/tmp/ --basedir=/tm
|
||||
|
||||
## Build
|
||||
|
||||
If on go < 1.11
|
||||
```bash
|
||||
go get -u -v ./...
|
||||
```
|
||||
|
||||
```bash
|
||||
go build -o transfersh main.go
|
||||
$ git clone git@github.com:dutchcoders/transfer.sh.git
|
||||
$ cd transfer.sh
|
||||
$ go build -o transfersh main.go
|
||||
```
|
||||
|
||||
## Docker
|
||||
@@ -151,7 +157,51 @@ If you specify the s3-region, you don't need to set the endpoint URL since the c
|
||||
|
||||
### Custom S3 providers
|
||||
|
||||
To use a custom non-AWS S3 provider, you need to specify the endpoint as definied from your cloud provider.
|
||||
To use a custom non-AWS S3 provider, you need to specify the endpoint as defined from your cloud provider.
|
||||
|
||||
## Storj Network Provider
|
||||
|
||||
To use the Storj Network as storage provider you need to specify the following flags:
|
||||
- provider `--provider storj`
|
||||
- storj-access _(either via flag or environment variable STORJ_ACCESS)_
|
||||
- storj-bucket _(either via flag or environment variable STORJ_BUCKET)_
|
||||
|
||||
### Creating Bucket and Scope
|
||||
|
||||
In preparation you need to create an access grant (or copy it from the uplink configuration) and a bucket.
|
||||
|
||||
To get started, login to your account and go to the Access Grant Menu and start the Wizard on the upper right.
|
||||
|
||||
Enter your access grant name of choice, hit *Next* and restrict it as necessary/preferred.
|
||||
Aftwards continue either in CLI or within the Browser. You'll be asked for a Passphrase used as Encryption Key.
|
||||
**Make sure to save it in a safe place, without it you will lose the ability to decrypt your files!**
|
||||
|
||||
Afterwards you can copy the access grant and then start the startup of the transfer.sh endpoint.
|
||||
For enhanced security its recommended to provide both the access grant and the bucket name as ENV Variables.
|
||||
|
||||
Example:
|
||||
```
|
||||
export STORJ_BUCKET=<BUCKET NAME>
|
||||
export STORJ_ACCESS=<ACCESS GRANT>
|
||||
transfer.sh --provider storj
|
||||
```
|
||||
|
||||
## Google Drive Usage
|
||||
|
||||
For the usage with Google drive, you need to specify the following options:
|
||||
- provider
|
||||
- gdrive-client-json-filepath
|
||||
- gdrive-local-config-path
|
||||
- basedir
|
||||
|
||||
### Creating Gdrive Client Json
|
||||
|
||||
You need to create a Oauth Client id from console.cloud.google.com
|
||||
download the file and place into a safe directory
|
||||
|
||||
### Usage example
|
||||
|
||||
```go run main.go --provider gdrive --basedir /tmp/ --gdrive-client-json-filepath /[credential_dir] --gdrive-local-config-path [directory_to_save_config] ```
|
||||
|
||||
## Contributions
|
||||
|
||||
@@ -169,7 +219,12 @@ Contributions are welcome.
|
||||
|
||||
**Andrea Spacca**
|
||||
|
||||
**Stefan Benten**
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Code and documentation copyright 2011-2018 Remco Verhoef.
|
||||
Code and documentation copyright 2018-2020 Andrea Spacca.
|
||||
Code and documentation copyright 2020- Andrea Spacca and Stefan Benten.
|
||||
|
||||
Code released under [the MIT license](LICENSE).
|
||||
|
248
cmd/cmd.go
248
cmd/cmd.go
@@ -12,7 +12,7 @@ import (
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
var Version = "1.1.2"
|
||||
var Version = "0.0.0"
|
||||
var helpTemplate = `NAME:
|
||||
{{.Name}} - {{.Usage}}
|
||||
|
||||
@@ -34,67 +34,86 @@ VERSION:
|
||||
|
||||
var globalFlags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "listener",
|
||||
Usage: "127.0.0.1:8080",
|
||||
Value: "127.0.0.1:8080",
|
||||
Name: "listener",
|
||||
Usage: "127.0.0.1:8080",
|
||||
Value: "127.0.0.1:8080",
|
||||
EnvVar: "LISTENER",
|
||||
},
|
||||
// redirect to https?
|
||||
// hostnames
|
||||
cli.StringFlag{
|
||||
Name: "profile-listener",
|
||||
Usage: "127.0.0.1:6060",
|
||||
Value: "",
|
||||
Name: "profile-listener",
|
||||
Usage: "127.0.0.1:6060",
|
||||
Value: "",
|
||||
EnvVar: "PROFILE_LISTENER",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "force-https",
|
||||
Usage: "",
|
||||
Name: "force-https",
|
||||
Usage: "",
|
||||
EnvVar: "FORCE_HTTPS",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-listener",
|
||||
Usage: "127.0.0.1:8443",
|
||||
Value: "",
|
||||
Name: "tls-listener",
|
||||
Usage: "127.0.0.1:8443",
|
||||
Value: "",
|
||||
EnvVar: "TLS_LISTENER",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "tls-listener-only",
|
||||
Usage: "",
|
||||
Name: "tls-listener-only",
|
||||
Usage: "",
|
||||
EnvVar: "TLS_LISTENER_ONLY",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-cert-file",
|
||||
Value: "",
|
||||
Name: "tls-cert-file",
|
||||
Value: "",
|
||||
EnvVar: "TLS_CERT_FILE",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "tls-private-key",
|
||||
Value: "",
|
||||
Name: "tls-private-key",
|
||||
Value: "",
|
||||
EnvVar: "TLS_PRIVATE_KEY",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "temp-path",
|
||||
Usage: "path to temp files",
|
||||
Value: os.TempDir(),
|
||||
Name: "temp-path",
|
||||
Usage: "path to temp files",
|
||||
Value: os.TempDir(),
|
||||
EnvVar: "TEMP_PATH",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "web-path",
|
||||
Usage: "path to static web files",
|
||||
Value: "",
|
||||
Name: "web-path",
|
||||
Usage: "path to static web files",
|
||||
Value: "",
|
||||
EnvVar: "WEB_PATH",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "proxy-path",
|
||||
Usage: "path prefix when service is run behind a proxy",
|
||||
Value: "",
|
||||
Name: "proxy-path",
|
||||
Usage: "path prefix when service is run behind a proxy",
|
||||
Value: "",
|
||||
EnvVar: "PROXY_PATH",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "ga-key",
|
||||
Usage: "key for google analytics (front end)",
|
||||
Value: "",
|
||||
Name: "proxy-port",
|
||||
Usage: "port of the proxy when the service is run behind a proxy",
|
||||
Value: "",
|
||||
EnvVar: "PROXY_PORT",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "uservoice-key",
|
||||
Usage: "key for user voice (front end)",
|
||||
Value: "",
|
||||
Name: "ga-key",
|
||||
Usage: "key for google analytics (front end)",
|
||||
Value: "",
|
||||
EnvVar: "GA_KEY",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "provider",
|
||||
Usage: "s3|gdrive|local",
|
||||
Value: "",
|
||||
Name: "uservoice-key",
|
||||
Usage: "key for user voice (front end)",
|
||||
Value: "",
|
||||
EnvVar: "USERVOICE_KEY",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "provider",
|
||||
Usage: "s3|gdrive|local",
|
||||
Value: "",
|
||||
EnvVar: "PROVIDER",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "s3-endpoint",
|
||||
@@ -127,33 +146,68 @@ var globalFlags = []cli.Flag{
|
||||
EnvVar: "BUCKET",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "s3-no-multipart",
|
||||
Usage: "Disables S3 Multipart Puts",
|
||||
Name: "s3-no-multipart",
|
||||
Usage: "Disables S3 Multipart Puts",
|
||||
EnvVar: "S3_NO_MULTIPART",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "s3-path-style",
|
||||
Usage: "Forces path style URLs, required for Minio.",
|
||||
Name: "s3-path-style",
|
||||
Usage: "Forces path style URLs, required for Minio.",
|
||||
EnvVar: "S3_PATH_STYLE",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "gdrive-client-json-filepath",
|
||||
Usage: "",
|
||||
Value: "",
|
||||
Name: "gdrive-client-json-filepath",
|
||||
Usage: "",
|
||||
Value: "",
|
||||
EnvVar: "GDRIVE_CLIENT_JSON_FILEPATH",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "gdrive-local-config-path",
|
||||
Usage: "",
|
||||
Value: "",
|
||||
Name: "gdrive-local-config-path",
|
||||
Usage: "",
|
||||
Value: "",
|
||||
EnvVar: "GDRIVE_LOCAL_CONFIG_PATH",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "gdrive-chunk-size",
|
||||
Usage: "",
|
||||
Value: googleapi.DefaultUploadChunkSize / 1024 / 1024,
|
||||
Name: "gdrive-chunk-size",
|
||||
Usage: "",
|
||||
Value: googleapi.DefaultUploadChunkSize / 1024 / 1024,
|
||||
EnvVar: "GDRIVE_CHUNK_SIZE",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "storj-access",
|
||||
Usage: "Access for the project",
|
||||
Value: "",
|
||||
EnvVar: "STORJ_ACCESS",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "storj-bucket",
|
||||
Usage: "Bucket to use within the project",
|
||||
Value: "",
|
||||
EnvVar: "STORJ_BUCKET",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "rate-limit",
|
||||
Usage: "requests per minute",
|
||||
Value: 0,
|
||||
EnvVar: "",
|
||||
EnvVar: "RATE_LIMIT",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "purge-days",
|
||||
Usage: "number of days after uploads are purged automatically",
|
||||
Value: 0,
|
||||
EnvVar: "PURGE_DAYS",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "purge-interval",
|
||||
Usage: "interval in hours to run the automatic purge for",
|
||||
Value: 0,
|
||||
EnvVar: "PURGE_INTERVAL",
|
||||
},
|
||||
cli.Int64Flag{
|
||||
Name: "max-upload-size",
|
||||
Usage: "max limit for upload, in kilobytes",
|
||||
Value: 0,
|
||||
EnvVar: "MAX_UPLOAD_SIZE",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "lets-encrypt-hosts",
|
||||
@@ -162,14 +216,16 @@ var globalFlags = []cli.Flag{
|
||||
EnvVar: "HOSTS",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "log",
|
||||
Usage: "/var/log/transfersh.log",
|
||||
Value: "",
|
||||
Name: "log",
|
||||
Usage: "/var/log/transfersh.log",
|
||||
Value: "",
|
||||
EnvVar: "LOG",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "basedir",
|
||||
Usage: "path to storage",
|
||||
Value: "",
|
||||
Name: "basedir",
|
||||
Usage: "path to storage",
|
||||
Value: "",
|
||||
EnvVar: "BASEDIR",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "clamav-host",
|
||||
@@ -184,28 +240,45 @@ var globalFlags = []cli.Flag{
|
||||
EnvVar: "VIRUSTOTAL_KEY",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "profiler",
|
||||
Usage: "enable profiling",
|
||||
Name: "profiler",
|
||||
Usage: "enable profiling",
|
||||
EnvVar: "PROFILER",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "http-auth-user",
|
||||
Usage: "user for http basic auth",
|
||||
Value: "",
|
||||
Name: "http-auth-user",
|
||||
Usage: "user for http basic auth",
|
||||
Value: "",
|
||||
EnvVar: "HTTP_AUTH_USER",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "http-auth-pass",
|
||||
Usage: "pass for http basic auth",
|
||||
Value: "",
|
||||
Name: "http-auth-pass",
|
||||
Usage: "pass for http basic auth",
|
||||
Value: "",
|
||||
EnvVar: "HTTP_AUTH_PASS",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "ip-whitelist",
|
||||
Usage: "comma separated list of ips allowed to connect to the service",
|
||||
Value: "",
|
||||
Name: "ip-whitelist",
|
||||
Usage: "comma separated list of ips allowed to connect to the service",
|
||||
Value: "",
|
||||
EnvVar: "IP_WHITELIST",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "ip-blacklist",
|
||||
Usage: "comma separated list of ips not allowed to connect to the service",
|
||||
Value: "",
|
||||
Name: "ip-blacklist",
|
||||
Usage: "comma separated list of ips not allowed to connect to the service",
|
||||
Value: "",
|
||||
EnvVar: "IP_BLACKLIST",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "cors-domains",
|
||||
Usage: "comma separated list of domains allowed for CORS requests",
|
||||
Value: "",
|
||||
EnvVar: "CORS_DOMAINS",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "random-token-length",
|
||||
Usage: "",
|
||||
Value: 6,
|
||||
EnvVar: "RANDOM_TOKEN_LENGTH",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -214,7 +287,7 @@ type Cmd struct {
|
||||
}
|
||||
|
||||
func VersionAction(c *cli.Context) {
|
||||
fmt.Println(color.YellowString(fmt.Sprintf("transfer.sh: Easy file sharing from the command line")))
|
||||
fmt.Println(color.YellowString(fmt.Sprintf("transfer.sh %s: Easy file sharing from the command line", Version)))
|
||||
}
|
||||
|
||||
func New() *Cmd {
|
||||
@@ -245,6 +318,10 @@ func New() *Cmd {
|
||||
options = append(options, server.Listener(v))
|
||||
}
|
||||
|
||||
if v := c.String("cors-domains"); v != "" {
|
||||
options = append(options, server.CorsDomains(v))
|
||||
}
|
||||
|
||||
if v := c.String("tls-listener"); v == "" {
|
||||
} else if c.Bool("tls-listener-only") {
|
||||
options = append(options, server.TLSListener(v, true))
|
||||
@@ -264,6 +341,10 @@ func New() *Cmd {
|
||||
options = append(options, server.ProxyPath(v))
|
||||
}
|
||||
|
||||
if v := c.String("proxy-port"); v != "" {
|
||||
options = append(options, server.ProxyPort(v))
|
||||
}
|
||||
|
||||
if v := c.String("ga-key"); v != "" {
|
||||
options = append(options, server.GoogleAnalytics(v))
|
||||
}
|
||||
@@ -294,10 +375,23 @@ func New() *Cmd {
|
||||
options = append(options, server.ClamavHost(v))
|
||||
}
|
||||
|
||||
if v := c.Int64("max-upload-size"); v > 0 {
|
||||
options = append(options, server.MaxUploadSize(v))
|
||||
}
|
||||
|
||||
if v := c.Int("rate-limit"); v > 0 {
|
||||
options = append(options, server.RateLimit(v))
|
||||
}
|
||||
|
||||
v := c.Int("random-token-length")
|
||||
options = append(options, server.RandomTokenLength(v))
|
||||
|
||||
purgeDays := c.Int("purge-days")
|
||||
purgeInterval := c.Int("purge-interval")
|
||||
if purgeDays > 0 && purgeInterval > 0 {
|
||||
options = append(options, server.Purge(purgeDays, purgeInterval))
|
||||
}
|
||||
|
||||
if cert := c.String("tls-cert-file"); cert == "" {
|
||||
} else if pk := c.String("tls-private-key"); pk == "" {
|
||||
} else {
|
||||
@@ -343,7 +437,7 @@ func New() *Cmd {
|
||||
panic("secret-key not set.")
|
||||
} else if bucket := c.String("bucket"); bucket == "" {
|
||||
panic("bucket not set.")
|
||||
} else if storage, err := server.NewS3Storage(accessKey, secretKey, bucket, c.String("s3-region"), c.String("s3-endpoint"), logger, c.Bool("s3-no-multipart"), c.Bool("s3-path-style")); err != nil {
|
||||
} else if storage, err := server.NewS3Storage(accessKey, secretKey, bucket, purgeDays, c.String("s3-region"), c.String("s3-endpoint"), c.Bool("s3-no-multipart"), c.Bool("s3-path-style"), logger); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
options = append(options, server.UseStorage(storage))
|
||||
@@ -362,6 +456,16 @@ func New() *Cmd {
|
||||
} else {
|
||||
options = append(options, server.UseStorage(storage))
|
||||
}
|
||||
case "storj":
|
||||
if access := c.String("storj-access"); access == "" {
|
||||
panic("storj-access not set.")
|
||||
} else if bucket := c.String("storj-bucket"); bucket == "" {
|
||||
panic("storj-bucket not set.")
|
||||
} else if storage, err := server.NewStorjStorage(access, bucket, purgeDays, logger); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
options = append(options, server.UseStorage(storage))
|
||||
}
|
||||
case "local":
|
||||
if v := c.String("basedir"); v == "" {
|
||||
panic("basedir not set.")
|
||||
|
33
fuzzit.sh
33
fuzzit.sh
@@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -xe
|
||||
|
||||
# Validate arguments
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 <fuzz-type>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Configure
|
||||
NAME=transfersh
|
||||
ROOT=./server
|
||||
TYPE=$1
|
||||
|
||||
# Setup
|
||||
export GO111MODULE="off"
|
||||
go get -u github.com/dvyukov/go-fuzz/go-fuzz github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||
go get -d -v -u ./...
|
||||
if [ ! -f fuzzit ]; then
|
||||
wget -q -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/download/v2.4.29/fuzzit_Linux_x86_64
|
||||
chmod a+x fuzzit
|
||||
fi
|
||||
|
||||
# Fuzz
|
||||
function fuzz {
|
||||
FUNC=Fuzz$1
|
||||
TARGET=$2
|
||||
DIR=${3:-$ROOT}
|
||||
go-fuzz-build -libfuzzer -func $FUNC -o fuzzer.a $DIR
|
||||
clang -fsanitize=fuzzer fuzzer.a -o fuzzer
|
||||
./fuzzit create job --type $TYPE $NAME/$TARGET fuzzer
|
||||
}
|
||||
fuzz LocalStorage local-storage
|
49
go.mod
49
go.mod
@@ -1,36 +1,37 @@
|
||||
module github.com/dutchcoders/transfer.sh
|
||||
|
||||
go 1.12
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.77.0 // indirect
|
||||
github.com/PuerkitoBio/ghost v0.0.0-20160324114900-206e6e460e14
|
||||
github.com/VojtechVitek/ratelimit v0.0.0-20160722140851-dc172bc0f6d2
|
||||
github.com/aws/aws-sdk-go v1.23.8
|
||||
github.com/aws/aws-sdk-go v1.37.14
|
||||
github.com/calebcase/tmpfile v1.0.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||
github.com/dutchcoders/go-virustotal v0.0.0-20140923143438-24cc8e6fa329
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20190716184912-96e06a2276ba
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/garyburd/redigo v1.6.0 // indirect
|
||||
github.com/golang/gddo v0.0.0-20190815223733-287de01127ef
|
||||
github.com/gorilla/mux v1.7.3
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210723094506-f0946ebceb7a
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1
|
||||
github.com/fatih/color v1.10.0
|
||||
github.com/garyburd/redigo v1.6.2 // indirect
|
||||
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||
github.com/mattn/go-isatty v0.0.9 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.2
|
||||
github.com/microcosm-cc/bluemonday v1.0.5
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9
|
||||
github.com/stretchr/testify v1.4.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
||||
github.com/urfave/cli v1.21.0
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
google.golang.org/api v0.9.0
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
|
||||
gopkg.in/russross/blackfriday.v2 v2.0.1
|
||||
github.com/urfave/cli v1.22.5
|
||||
go.opencensus.io v0.22.6 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99
|
||||
google.golang.org/api v0.40.0
|
||||
google.golang.org/genproto v0.0.0-20210218151259-fe80b386bf06 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
|
||||
storj.io/common v0.0.0-20210504141454-bcb03a80052f
|
||||
storj.io/uplink v1.5.0-rc.1.0.20210512164354-e2e5889614a9
|
||||
)
|
||||
|
||||
replace gopkg.in/russross/blackfriday.v2 v2.0.1 => github.com/russross/blackfriday/v2 v2.0.1
|
||||
|
563
go.sum
563
go.sum
@@ -1,154 +1,611 @@
|
||||
cloud.google.com/go v0.16.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.77.0 h1:qA5V5+uQf6Mgr+tmFI8UT3D/ELyhIYkPwNGao/3Y+sQ=
|
||||
cloud.google.com/go v0.77.0/go.mod h1:R8fYSLIilC247Iu8WS2OGHw1E/Ufn7Pd7HiDjTqiURs=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/PuerkitoBio/ghost v0.0.0-20160324114900-206e6e460e14 h1:3zOOc7WdrATDXof+h/rBgMsg0sAmZIEVHft1UbWHh94=
|
||||
github.com/PuerkitoBio/ghost v0.0.0-20160324114900-206e6e460e14/go.mod h1:+VFiaivV54Sa94ijzA/ZHQLoHuoUIS9hIqCK6f/76Zw=
|
||||
github.com/VojtechVitek/ratelimit v0.0.0-20160722140851-dc172bc0f6d2 h1:sIvihcW4qpN5qGSjmrsDDAbLpEq5tuHjJJfWY0Hud5Y=
|
||||
github.com/VojtechVitek/ratelimit v0.0.0-20160722140851-dc172bc0f6d2/go.mod h1:3YwJE8rEisS9eraee0hygGG4G3gqX8H8Nyu+nPTUnGU=
|
||||
github.com/aws/aws-sdk-go v1.23.8 h1:G/azJoBN0pnhB3B+0eeC4yyVFYIIad6bbzg6wwtImqk=
|
||||
github.com/aws/aws-sdk-go v1.23.8/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/aws/aws-sdk-go v1.37.14 h1:thuR1hd1doCvsaMDYDMhqCGSmw39bSvZaw+DPGhMm5w=
|
||||
github.com/aws/aws-sdk-go v1.37.14/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
||||
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ=
|
||||
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/calebcase/tmpfile v1.0.2-0.20200602150926-3af473ef8439/go.mod h1:iErLeG/iqJr8LaQ/gYRv4GXdqssi3jg4iSzvrA06/lw=
|
||||
github.com/calebcase/tmpfile v1.0.2 h1:1AGuhKiUu4J6wxz6lxuF6ck3f8G2kaV6KSEny0RGCig=
|
||||
github.com/calebcase/tmpfile v1.0.2/go.mod h1:iErLeG/iqJr8LaQ/gYRv4GXdqssi3jg4iSzvrA06/lw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
|
||||
github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e h1:rcHHSQqzCgvlwP0I/fQ8rQMn/MpHE5gWSLdtpxtP6KQ=
|
||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e/go.mod h1:Byz7q8MSzSPkouskHJhX0er2mZY/m0Vj5bMeMCkkyY4=
|
||||
github.com/dutchcoders/go-virustotal v0.0.0-20140923143438-24cc8e6fa329 h1:ERqCkG/uSyT74P1m/j9yR+so+7ynY4fbTvLY/Mr1ZMg=
|
||||
github.com/dutchcoders/go-virustotal v0.0.0-20140923143438-24cc8e6fa329/go.mod h1:G5qOfE5bQZ5scycLpB7fYWgN4y3xdfXo+pYWM8z2epY=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20190716184912-96e06a2276ba h1:474BcGUqYKnxg49p7O7i3m9EuFfOag+OtPw5b/nmGVk=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20190716184912-96e06a2276ba/go.mod h1:UjR1zlrq/R2Sef7e4q3TeJm4HcbLh4vRzlCEGJP+wLg=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
|
||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/golang/gddo v0.0.0-20190815223733-287de01127ef h1:4NNI5xhPnmBogD0yj/BV20wSHOg+7YcxX+JyX1tGVn8=
|
||||
github.com/golang/gddo v0.0.0-20190815223733-287de01127ef/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210723094506-f0946ebceb7a h1:+N7J1NK7gxKZ+X4syY1HqafUudJiR8voJGcXWkxLgAw=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210723094506-f0946ebceb7a/go.mod h1:F6Q37CxDh2MHr5KXkcZmNB3tdkK7v+bgE+OpBY+9ilI=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
|
||||
github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.4.3-0.20170329110642-4da3e2cfbabc/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/garyburd/redigo v1.6.2 h1:yE/pwKCrbLpLpQICzYTeZ7JsTA/C53wFTJHaEtRqniM=
|
||||
github.com/garyburd/redigo v1.6.2/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f h1:16RtHeWGkJMc80Etb8RPCcKevXGldr57+LOyZt8zOlg=
|
||||
github.com/golang/gddo v0.0.0-20210115222349-20d68f94ee1f/go.mod h1:ijRvpgDJDI262hYq/IQVYgf8hd8IHUs93Ol0kvMBAx4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/lint v0.0.0-20170918230701-e5d664eb928e/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.1.1-0.20171103154506-982329095285/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gregjones/httpcache v0.0.0-20170920190843-316c5e0ff04e/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
||||
github.com/magiconair/properties v1.7.4-0.20170902060319-8d7837e64d3c/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/microcosm-cc/bluemonday v1.0.5 h1:cF59UCKMmmUgqN1baLvqU/B1ZsMori+duLVTLpgiG3w=
|
||||
github.com/microcosm-cc/bluemonday v1.0.5/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
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/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
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/shuLhan/go-bindata v4.0.0+incompatible/go.mod h1:pkcPAATLBDD2+SpAPnX5vEM90F7fcwHCvvLCMXcmw3g=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE=
|
||||
github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo=
|
||||
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/spacemonkeygo/monkit/v3 v3.0.4/go.mod h1:JcK1pCbReQsOsMKF/POFSZCq7drXFybgGmbc27tuwes=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.7/go.mod h1:kj1ViJhlyADa7DiA4xVnTuPA46lFKbM7mxQTrXCuJP4=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.10 h1:jJPiF4EdetQAHAyHyX0wYIv9c/Vl0oN3KJKtnakfR+A=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.10/go.mod h1:kj1ViJhlyADa7DiA4xVnTuPA46lFKbM7mxQTrXCuJP4=
|
||||
github.com/spacemonkeygo/monotime v0.0.0-20180824235756-e3f48a95f98a/go.mod h1:ul4bvvnCOPZgq8w0nTkSmWVg/hauVpFS97Am1YM1XXo=
|
||||
github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
|
||||
github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.1-0.20170901120850-7aff26db30c1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
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/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
|
||||
github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE=
|
||||
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
|
||||
go.opencensus.io v0.21.0 h1:mU6zScU4U1YAFPHEHYk+3JC4SY7JxgkqS10ZOSyksNg=
|
||||
github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU=
|
||||
github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3 h1:zMsHhfK9+Wdl1F7sIKLyx3wrOFofpb3rWFbA4HgcK5k=
|
||||
github.com/vivint/infectious v0.0.0-20200605153912-25a574ae18a3/go.mod h1:R0Gbuw7ElaGSLOZUSwBm/GgVwMd30jWxBDdAyMOeTuc=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/zeebo/admission/v3 v3.0.2/go.mod h1:BP3isIv9qa2A7ugEratNq1dnl2oZRXaQUGdU7WXKtbw=
|
||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/errs v1.2.2 h1:5NFypMTuSdoySVTqlNs1dEoU21QVamMQJxW/Fii5O7g=
|
||||
github.com/zeebo/errs v1.2.2/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
github.com/zeebo/float16 v0.1.0/go.mod h1:fssGvvXu+XS8MH57cKmyrLB/cqioYeYX/2mXCN3a5wo=
|
||||
github.com/zeebo/incenc v0.0.0-20180505221441-0d92902eec54/go.mod h1:EI8LcOBDlSL3POyqwC1eJhOYlMBMidES+613EtmmT5w=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.22.6 h1:BdkrbWrzDlV9dnbzoP7sfN+dHheJ4J9JOaYxcUDL+ok=
|
||||
go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc h1:+q90ECDSAQirdykUN6sPEiBXBsp8Csjcca8Oy7bgLTA=
|
||||
golang.org/x/crypto v0.0.0-20210415154028-4f45737414dc/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210113205817-d3ed898aa8a3/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99 h1:5vD4XjIc0X5+kHZjx4UecYdjA6mJo+XXNoaW0EjU5Os=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20170517211232-f52d1811a629/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe h1:WdX7u8s3yOigWAhHEaDl8r9G+4XwFQEQFtBMYyN+kXQ=
|
||||
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20170921000349-586095a6e407/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.9.0 h1:jbyannxz0XFD3zdjgrSUsaJbgpH4eTrkdhRChkHPfO8=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0 h1:uWrpz12dpVPn7cojP82mk02XDgTJLDPc2KbVTxrWb4A=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20170918111702-1e559d0a00ee/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873 h1:nfPFGzJkUDX6uBmpN/pSw7MbOAWegH5QDQuoXFHedLg=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210212180131-e7f2df4ecc2d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210218151259-fe80b386bf06 h1:Px6YyLaNKEo5eoniIBAv6Es0jbvyEmSYqOac64iS2Rs=
|
||||
google.golang.org/genproto v0.0.0-20210218151259-fe80b386bf06/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.2.1-0.20170921194603-d4b75ebd4f9f/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1 h1:Hz2g2wirWK7H0qIIhGIqRGTuMwTE8HEKFnDZZ7lm9NU=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/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=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
storj.io/common v0.0.0-20210504141454-bcb03a80052f h1:TwWEzxjvhnkCKUGds4HQKtAgFBjzf/C0hcA1luiNuKI=
|
||||
storj.io/common v0.0.0-20210504141454-bcb03a80052f/go.mod h1:PdP3eTld9RqSV3E4K44JSlw7Z/zNsymj9rnKuHFKhJE=
|
||||
storj.io/drpc v0.0.20 h1:nzOxsetLi0fJ8xCL92LPlYL0B6iYdDDk1Cpdbn0/r9Y=
|
||||
storj.io/drpc v0.0.20/go.mod h1:eAxUDk8HWvGl9iqznpuphtZ+WIjIGPJFqNXuKHgRiMM=
|
||||
storj.io/uplink v1.5.0-rc.1.0.20210512164354-e2e5889614a9 h1:F+A+Ki4eo3uzYXxesihRBq7PYBhU8MgfZeebd4O8hio=
|
||||
storj.io/uplink v1.5.0-rc.1.0.20210512164354-e2e5889614a9/go.mod h1:geRW2dh4rvPhgruFZbN71LSYkMmCJLpwg0y8K/uLr3Y=
|
||||
|
@@ -2,6 +2,8 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2017 DutchCoders [https://github.com/dutchcoders/]
|
||||
Copyright (c) 2018-2020 Andrea Spacca.
|
||||
Copyright (c) 2020- Andrea Spacca and Stefan Benten.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -30,7 +32,6 @@ import (
|
||||
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -58,7 +59,7 @@ func (s *Server) scanHandler(w http.ResponseWriter, r *http.Request) {
|
||||
abort := make(chan bool)
|
||||
response, err := c.ScanStream(reader, abort)
|
||||
if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
https://github.com/fs111/kurz.go/blob/master/src/codec.go
|
||||
|
||||
Originally written and Copyright (c) 2011 André Kelpe
|
||||
Modifications Copyright (c) 2015 John Ko
|
||||
|
||||
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 server
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// characters used for short-urls
|
||||
SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
// someone set us up the bomb !!
|
||||
BASE = int64(len(SYMBOLS))
|
||||
)
|
||||
|
||||
// encodes a number into our *base* representation
|
||||
// TODO can this be made better with some bitshifting?
|
||||
func Encode(number int64) string {
|
||||
rest := number % BASE
|
||||
// strings are a bit weird in go...
|
||||
result := string(SYMBOLS[rest])
|
||||
if number-rest != 0 {
|
||||
newnumber := (number - rest) / BASE
|
||||
result = Encode(newnumber) + result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Decodes a string given in our encoding and returns the decimal
|
||||
// integer.
|
||||
func Decode(input string) int64 {
|
||||
const floatbase = float64(BASE)
|
||||
l := len(input)
|
||||
var sum int = 0
|
||||
for index := l - 1; index > -1; index -= 1 {
|
||||
current := string(input[index])
|
||||
pos := strings.Index(SYMBOLS, current)
|
||||
sum = sum + (pos * int(math.Pow(floatbase, float64((l-index-1)))))
|
||||
}
|
||||
return int64(sum)
|
||||
}
|
@@ -2,6 +2,8 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2017 DutchCoders [https://github.com/dutchcoders/]
|
||||
Copyright (c) 2018-2020 Andrea Spacca.
|
||||
Copyright (c) 2020- Andrea Spacca and Stefan Benten.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -35,13 +37,11 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
blackfriday "gopkg.in/russross/blackfriday.v2"
|
||||
blackfriday "github.com/russross/blackfriday/v2"
|
||||
"html"
|
||||
html_template "html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -95,6 +95,27 @@ func healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Approaching Neutral Zone, all systems normal and functioning.")
|
||||
}
|
||||
|
||||
func canContainsXSS(contentType string) bool {
|
||||
switch {
|
||||
case strings.Contains(contentType, "cache-manifest"):
|
||||
fallthrough
|
||||
case strings.Contains(contentType, "html"):
|
||||
fallthrough
|
||||
case strings.Contains(contentType, "rdf"):
|
||||
fallthrough
|
||||
case strings.Contains(contentType, "vtt"):
|
||||
fallthrough
|
||||
case strings.Contains(contentType, "xml"):
|
||||
fallthrough
|
||||
case strings.Contains(contentType, "xsl"):
|
||||
return true
|
||||
case strings.Contains(contentType, "x-mixed-replace"):
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/* The preview handler will show a preview of the content for browsers (accept type text/html), and referer is not transfer.sh */
|
||||
func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
@@ -102,15 +123,16 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
token := vars["token"]
|
||||
filename := vars["filename"]
|
||||
|
||||
_, err := s.CheckMetadata(token, filename, false)
|
||||
metadata, err := s.CheckMetadata(token, filename, false)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error metadata: %s", err.Error())
|
||||
s.logger.Printf("Error metadata: %s", err.Error())
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
contentType, contentLength, err := s.storage.Head(token, filename)
|
||||
contentType := metadata.ContentType
|
||||
contentLength, err := s.storage.Head(token, filename)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
@@ -130,7 +152,7 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
templatePath = "download.markdown.html"
|
||||
|
||||
var reader io.ReadCloser
|
||||
if reader, _, _, err = s.storage.Get(token, filename); err != nil {
|
||||
if reader, _, err = s.storage.Get(token, filename); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -157,9 +179,9 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
|
||||
resolvedURL := resolveURL(r, relativeURL)
|
||||
resolvedURL := resolveURL(r, relativeURL, s.proxyPort)
|
||||
relativeURLGet, _ := url.Parse(path.Join(s.proxyPath, getPathPart, token, filename))
|
||||
resolvedURLGet := resolveURL(r, relativeURLGet)
|
||||
resolvedURLGet := resolveURL(r, relativeURLGet, s.proxyPort)
|
||||
var png []byte
|
||||
png, err = qrcode.Encode(resolvedURL, qrcode.High, 150)
|
||||
if err != nil {
|
||||
@@ -169,27 +191,29 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
qrCode := base64.StdEncoding.EncodeToString(png)
|
||||
|
||||
hostname := getURL(r).Host
|
||||
webAddress := resolveWebAddress(r, s.proxyPath)
|
||||
hostname := getURL(r, s.proxyPort).Host
|
||||
webAddress := resolveWebAddress(r, s.proxyPath, s.proxyPort)
|
||||
|
||||
data := struct {
|
||||
ContentType string
|
||||
Content html_template.HTML
|
||||
Filename string
|
||||
Url string
|
||||
UrlGet string
|
||||
Hostname string
|
||||
WebAddress string
|
||||
ContentLength uint64
|
||||
GAKey string
|
||||
UserVoiceKey string
|
||||
QRCode string
|
||||
ContentType string
|
||||
Content html_template.HTML
|
||||
Filename string
|
||||
Url string
|
||||
UrlGet string
|
||||
UrlRandomToken string
|
||||
Hostname string
|
||||
WebAddress string
|
||||
ContentLength uint64
|
||||
GAKey string
|
||||
UserVoiceKey string
|
||||
QRCode string
|
||||
}{
|
||||
contentType,
|
||||
content,
|
||||
filename,
|
||||
resolvedURL,
|
||||
resolvedURLGet,
|
||||
token,
|
||||
hostname,
|
||||
webAddress,
|
||||
contentLength,
|
||||
@@ -211,19 +235,37 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) viewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// vars := mux.Vars(r)
|
||||
|
||||
hostname := getURL(r).Host
|
||||
webAddress := resolveWebAddress(r, s.proxyPath)
|
||||
hostname := getURL(r, s.proxyPort).Host
|
||||
webAddress := resolveWebAddress(r, s.proxyPath, s.proxyPort)
|
||||
|
||||
maxUploadSize := ""
|
||||
if s.maxUploadSize > 0 {
|
||||
maxUploadSize = formatSize(s.maxUploadSize)
|
||||
}
|
||||
|
||||
purgeTime := ""
|
||||
if s.purgeDays > 0 {
|
||||
purgeTime = s.purgeDays.String()
|
||||
}
|
||||
|
||||
data := struct {
|
||||
Hostname string
|
||||
WebAddress string
|
||||
GAKey string
|
||||
UserVoiceKey string
|
||||
Hostname string
|
||||
WebAddress string
|
||||
GAKey string
|
||||
UserVoiceKey string
|
||||
PurgeTime string
|
||||
MaxUploadSize string
|
||||
SampleToken string
|
||||
SampleToken2 string
|
||||
}{
|
||||
hostname,
|
||||
webAddress,
|
||||
s.gaKey,
|
||||
s.userVoiceKey,
|
||||
purgeTime,
|
||||
maxUploadSize,
|
||||
Token(s.randomTokenLength),
|
||||
Token(s.randomTokenLength),
|
||||
}
|
||||
|
||||
if acceptsHTML(r.Header) {
|
||||
@@ -249,29 +291,25 @@ func sanitize(fileName string) string {
|
||||
|
||||
func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseMultipartForm(_24K); nil != err {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Error occurred copying to output stream", 500)
|
||||
return
|
||||
}
|
||||
|
||||
token := Encode(10000000 + int64(rand.Intn(1000000000)))
|
||||
token := Token(s.randomTokenLength)
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
|
||||
for _, fheaders := range r.MultipartForm.File {
|
||||
for _, fheader := range fheaders {
|
||||
filename := sanitize(fheader.Filename)
|
||||
contentType := fheader.Header.Get("Content-Type")
|
||||
|
||||
if contentType == "" {
|
||||
contentType = mime.TypeByExtension(filepath.Ext(fheader.Filename))
|
||||
}
|
||||
contentType := mime.TypeByExtension(filepath.Ext(fheader.Filename))
|
||||
|
||||
var f io.Reader
|
||||
var err error
|
||||
|
||||
if f, err = fheader.Open(); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
@@ -280,7 +318,7 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
n, err := io.CopyN(&b, f, _24K+1)
|
||||
if err != nil && err != io.EOF {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
@@ -291,14 +329,14 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if n > _24K {
|
||||
file, err = ioutil.TempFile(s.tempPath, "transfer-")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
s.logger.Fatal(err)
|
||||
}
|
||||
|
||||
n, err = io.Copy(file, io.MultiReader(&b, f))
|
||||
if err != nil {
|
||||
cleanTmpFile(file)
|
||||
s.cleanTmpFile(file)
|
||||
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
@@ -310,27 +348,33 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
contentLength := n
|
||||
|
||||
metadata := MetadataForRequest(contentType, r)
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
http.Error(w, errors.New("Could not encode metadata").Error(), 500)
|
||||
|
||||
cleanTmpFile(file)
|
||||
return
|
||||
} else if err := s.storage.Put(token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
http.Error(w, errors.New("Could not save metadata").Error(), 500)
|
||||
|
||||
cleanTmpFile(file)
|
||||
if s.maxUploadSize > 0 && contentLength > s.maxUploadSize {
|
||||
s.logger.Print("Entity too large")
|
||||
http.Error(w, http.StatusText(http.StatusRequestEntityTooLarge), http.StatusRequestEntityTooLarge)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
|
||||
metadata := MetadataForRequest(contentType, s.randomTokenLength, r)
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, errors.New("Could not encode metadata").Error(), 500)
|
||||
|
||||
s.cleanTmpFile(file)
|
||||
return
|
||||
} else if err := s.storage.Put(token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, errors.New("Could not save metadata").Error(), 500)
|
||||
|
||||
s.cleanTmpFile(file)
|
||||
return
|
||||
}
|
||||
|
||||
s.logger.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
|
||||
|
||||
if err = s.storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil {
|
||||
log.Printf("Backend storage error: %s", err.Error())
|
||||
s.logger.Printf("Backend storage error: %s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
|
||||
@@ -338,23 +382,23 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
filename = url.PathEscape(filename)
|
||||
relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
|
||||
fmt.Fprintln(w, getURL(r).ResolveReference(relativeURL).String())
|
||||
fmt.Fprintln(w, getURL(r, s.proxyPort).ResolveReference(relativeURL).String())
|
||||
|
||||
cleanTmpFile(file)
|
||||
s.cleanTmpFile(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cleanTmpFile(f *os.File) {
|
||||
func (s *Server) cleanTmpFile(f *os.File) {
|
||||
if f != nil {
|
||||
err := f.Close()
|
||||
if err != nil {
|
||||
log.Printf("Error closing tmpfile: %s (%s)", err, f.Name())
|
||||
s.logger.Printf("Error closing tmpfile: %s (%s)", err, f.Name())
|
||||
}
|
||||
|
||||
err = os.Remove(f.Name())
|
||||
if err != nil {
|
||||
log.Printf("Error removing tmpfile: %s (%s)", err, f.Name())
|
||||
s.logger.Printf("Error removing tmpfile: %s (%s)", err, f.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -374,13 +418,13 @@ type Metadata struct {
|
||||
DeletionToken string
|
||||
}
|
||||
|
||||
func MetadataForRequest(contentType string, r *http.Request) Metadata {
|
||||
func MetadataForRequest(contentType string, randomTokenLength int, r *http.Request) Metadata {
|
||||
metadata := Metadata{
|
||||
ContentType: contentType,
|
||||
ContentType: strings.ToLower(contentType),
|
||||
MaxDate: time.Time{},
|
||||
Downloads: 0,
|
||||
MaxDownloads: -1,
|
||||
DeletionToken: Encode(10000000+int64(rand.Intn(1000000000))) + Encode(10000000+int64(rand.Intn(1000000000))),
|
||||
DeletionToken: Token(randomTokenLength) + Token(randomTokenLength),
|
||||
}
|
||||
|
||||
if v := r.Header.Get("Max-Downloads"); v == "" {
|
||||
@@ -422,7 +466,7 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
n, err := io.CopyN(&b, f, _24K+1)
|
||||
if err != nil && err != io.EOF {
|
||||
log.Printf("Error putting new file: %s", err.Error())
|
||||
s.logger.Printf("Error putting new file: %s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
@@ -432,16 +476,16 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if n > _24K {
|
||||
file, err = ioutil.TempFile(s.tempPath, "transfer-")
|
||||
if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
defer cleanTmpFile(file)
|
||||
defer s.cleanTmpFile(file)
|
||||
|
||||
n, err = io.Copy(file, io.MultiReader(&b, f))
|
||||
if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
@@ -454,39 +498,41 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {
|
||||
contentLength = n
|
||||
}
|
||||
|
||||
if s.maxUploadSize > 0 && contentLength > s.maxUploadSize {
|
||||
s.logger.Print("Entity too large")
|
||||
http.Error(w, http.StatusText(http.StatusRequestEntityTooLarge), http.StatusRequestEntityTooLarge)
|
||||
return
|
||||
}
|
||||
|
||||
if contentLength == 0 {
|
||||
log.Print("Empty content-length")
|
||||
s.logger.Print("Empty content-length")
|
||||
http.Error(w, errors.New("Could not upload empty file").Error(), 400)
|
||||
return
|
||||
}
|
||||
|
||||
contentType := r.Header.Get("Content-Type")
|
||||
contentType := mime.TypeByExtension(filepath.Ext(vars["filename"]))
|
||||
|
||||
if contentType == "" {
|
||||
contentType = mime.TypeByExtension(filepath.Ext(vars["filename"]))
|
||||
}
|
||||
token := Token(s.randomTokenLength)
|
||||
|
||||
token := Encode(10000000 + int64(rand.Intn(1000000000)))
|
||||
|
||||
metadata := MetadataForRequest(contentType, r)
|
||||
metadata := MetadataForRequest(contentType, s.randomTokenLength, r)
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, errors.New("Could not encode metadata").Error(), 500)
|
||||
return
|
||||
} else if err := s.storage.Put(token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, errors.New("Could not save metadata").Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
|
||||
s.logger.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
|
||||
|
||||
var err error
|
||||
|
||||
if err = s.storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil {
|
||||
log.Printf("Error putting new file: %s", err.Error())
|
||||
s.logger.Printf("Error putting new file: %s", err.Error())
|
||||
http.Error(w, errors.New("Could not save file").Error(), 500)
|
||||
return
|
||||
}
|
||||
@@ -499,15 +545,15 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {
|
||||
relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
|
||||
deleteURL, _ := url.Parse(path.Join(s.proxyPath, token, filename, metadata.DeletionToken))
|
||||
|
||||
w.Header().Set("X-Url-Delete", resolveURL(r, deleteURL))
|
||||
w.Header().Set("X-Url-Delete", resolveURL(r, deleteURL, s.proxyPort))
|
||||
|
||||
fmt.Fprint(w, resolveURL(r, relativeURL))
|
||||
fmt.Fprint(w, resolveURL(r, relativeURL, s.proxyPort))
|
||||
}
|
||||
|
||||
func resolveURL(r *http.Request, u *url.URL) string {
|
||||
func resolveURL(r *http.Request, u *url.URL, proxyPort string) string {
|
||||
r.URL.Path = ""
|
||||
|
||||
return getURL(r).ResolveReference(u).String()
|
||||
return getURL(r, proxyPort).ResolveReference(u).String()
|
||||
}
|
||||
|
||||
func resolveKey(key, proxyPath string) string {
|
||||
@@ -524,8 +570,8 @@ func resolveKey(key, proxyPath string) string {
|
||||
return key
|
||||
}
|
||||
|
||||
func resolveWebAddress(r *http.Request, proxyPath string) string {
|
||||
url := getURL(r)
|
||||
func resolveWebAddress(r *http.Request, proxyPath string, proxyPort string) string {
|
||||
url := getURL(r, proxyPort)
|
||||
|
||||
var webAddress string
|
||||
|
||||
@@ -543,8 +589,22 @@ func resolveWebAddress(r *http.Request, proxyPath string) string {
|
||||
return webAddress
|
||||
}
|
||||
|
||||
func getURL(r *http.Request) *url.URL {
|
||||
u, _ := url.Parse(r.URL.String())
|
||||
// Similar to the logic found here:
|
||||
// https://github.com/golang/go/blob/release-branch.go1.14/src/net/http/clone.go#L22-L33
|
||||
func cloneURL(u *url.URL) *url.URL {
|
||||
c := &url.URL{}
|
||||
*c = *u
|
||||
|
||||
if u.User != nil {
|
||||
c.User = &url.Userinfo{}
|
||||
*c.User = *u.User
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func getURL(r *http.Request, proxyPort string) *url.URL {
|
||||
u := cloneURL(r.URL)
|
||||
|
||||
if r.TLS != nil {
|
||||
u.Scheme = "https"
|
||||
@@ -554,16 +614,25 @@ func getURL(r *http.Request) *url.URL {
|
||||
u.Scheme = "http"
|
||||
}
|
||||
|
||||
if u.Host != "" {
|
||||
} else if host, port, err := net.SplitHostPort(r.Host); err != nil {
|
||||
u.Host = r.Host
|
||||
} else {
|
||||
if port == "80" && u.Scheme == "http" {
|
||||
u.Host = host
|
||||
} else if port == "443" && u.Scheme == "https" {
|
||||
if u.Host == "" {
|
||||
host, port, err := net.SplitHostPort(r.Host)
|
||||
if err != nil {
|
||||
host = r.Host
|
||||
port = ""
|
||||
}
|
||||
if len(proxyPort) != 0 {
|
||||
port = proxyPort
|
||||
}
|
||||
if len(port) == 0 {
|
||||
u.Host = host
|
||||
} else {
|
||||
u.Host = net.JoinHostPort(host, port)
|
||||
if port == "80" && u.Scheme == "http" {
|
||||
u.Host = host
|
||||
} else if port == "443" && u.Scheme == "https" {
|
||||
u.Host = host
|
||||
} else {
|
||||
u.Host = net.JoinHostPort(host, port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,23 +656,22 @@ func (metadata Metadata) remainingLimitHeaderValues() (remainingDownloads, remai
|
||||
return remainingDownloads, remainingDays
|
||||
}
|
||||
|
||||
func (s *Server) Lock(token, filename string) error {
|
||||
func (s *Server) Lock(token, filename string) {
|
||||
key := path.Join(token, filename)
|
||||
|
||||
if _, ok := s.locks[key]; !ok {
|
||||
s.locks[key] = &sync.Mutex{}
|
||||
}
|
||||
lock, _ := s.locks.LoadOrStore(key, &sync.Mutex{})
|
||||
|
||||
s.locks[key].Lock()
|
||||
lock.(*sync.Mutex).Lock()
|
||||
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Server) Unlock(token, filename string) error {
|
||||
func (s *Server) Unlock(token, filename string) {
|
||||
key := path.Join(token, filename)
|
||||
s.locks[key].Unlock()
|
||||
|
||||
return nil
|
||||
lock, _ := s.locks.LoadOrStore(key, &sync.Mutex{})
|
||||
|
||||
lock.(*sync.Mutex).Unlock()
|
||||
}
|
||||
|
||||
func (s *Server) CheckMetadata(token, filename string, increaseDownload bool) (Metadata, error) {
|
||||
@@ -612,10 +680,8 @@ func (s *Server) CheckMetadata(token, filename string, increaseDownload bool) (M
|
||||
|
||||
var metadata Metadata
|
||||
|
||||
r, _, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename))
|
||||
if s.storage.IsNotExist(err) {
|
||||
return metadata, nil
|
||||
} else if err != nil {
|
||||
r, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename))
|
||||
if err != nil {
|
||||
return metadata, err
|
||||
}
|
||||
|
||||
@@ -627,13 +693,11 @@ func (s *Server) CheckMetadata(token, filename string, increaseDownload bool) (M
|
||||
return metadata, errors.New("MaxDownloads expired.")
|
||||
} else if !metadata.MaxDate.IsZero() && time.Now().After(metadata.MaxDate) {
|
||||
return metadata, errors.New("MaxDate expired.")
|
||||
} else {
|
||||
} else if metadata.MaxDownloads != -1 && increaseDownload {
|
||||
// todo(nl5887): mutex?
|
||||
|
||||
// update number of downloads
|
||||
if increaseDownload {
|
||||
metadata.Downloads++
|
||||
}
|
||||
metadata.Downloads++
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
|
||||
@@ -652,9 +716,9 @@ func (s *Server) CheckDeletionToken(deletionToken, token, filename string) error
|
||||
|
||||
var metadata Metadata
|
||||
|
||||
r, _, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename))
|
||||
r, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename))
|
||||
if s.storage.IsNotExist(err) {
|
||||
return nil
|
||||
return errors.New("Metadata doesn't exist")
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -670,6 +734,19 @@ func (s *Server) CheckDeletionToken(deletionToken, token, filename string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) purgeHandler() {
|
||||
ticker := time.NewTicker(s.purgeInterval)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
err := s.storage.Purge(s.purgeDays)
|
||||
s.logger.Printf("error cleaning up expired files: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *Server) deleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
@@ -678,7 +755,7 @@ func (s *Server) deleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
deletionToken := vars["deletionToken"]
|
||||
|
||||
if err := s.CheckDeletionToken(deletionToken, token, filename); err != nil {
|
||||
log.Printf("Error metadata: %s", err.Error())
|
||||
s.logger.Printf("Error metadata: %s", err.Error())
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
@@ -688,7 +765,7 @@ func (s *Server) deleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not delete file.", 500)
|
||||
return
|
||||
}
|
||||
@@ -714,18 +791,18 @@ func (s *Server) zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
filename := sanitize(strings.Split(key, "/")[1])
|
||||
|
||||
if _, err := s.CheckMetadata(token, filename, true); err != nil {
|
||||
log.Printf("Error metadata: %s", err.Error())
|
||||
s.logger.Printf("Error metadata: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
reader, _, _, err := s.storage.Get(token, filename)
|
||||
reader, _, err := s.storage.Get(token, filename)
|
||||
|
||||
if err != nil {
|
||||
if s.storage.IsNotExist(err) {
|
||||
http.Error(w, "File not found", 404)
|
||||
return
|
||||
} else {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
return
|
||||
}
|
||||
@@ -743,20 +820,20 @@ func (s *Server) zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
fw, err := zw.CreateHeader(header)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(fw, reader); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := zw.Close(); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
}
|
||||
@@ -786,17 +863,17 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
filename := sanitize(strings.Split(key, "/")[1])
|
||||
|
||||
if _, err := s.CheckMetadata(token, filename, true); err != nil {
|
||||
log.Printf("Error metadata: %s", err.Error())
|
||||
s.logger.Printf("Error metadata: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
reader, _, contentLength, err := s.storage.Get(token, filename)
|
||||
reader, contentLength, err := s.storage.Get(token, filename)
|
||||
if err != nil {
|
||||
if s.storage.IsNotExist(err) {
|
||||
http.Error(w, "File not found", 404)
|
||||
return
|
||||
} else {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
return
|
||||
}
|
||||
@@ -811,13 +888,13 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
err = zw.WriteHeader(header)
|
||||
if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(zw, reader); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
}
|
||||
@@ -845,17 +922,17 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
filename := strings.Split(key, "/")[1]
|
||||
|
||||
if _, err := s.CheckMetadata(token, filename, true); err != nil {
|
||||
log.Printf("Error metadata: %s", err.Error())
|
||||
s.logger.Printf("Error metadata: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
reader, _, contentLength, err := s.storage.Get(token, filename)
|
||||
reader, contentLength, err := s.storage.Get(token, filename)
|
||||
if err != nil {
|
||||
if s.storage.IsNotExist(err) {
|
||||
http.Error(w, "File not found", 404)
|
||||
return
|
||||
} else {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
return
|
||||
}
|
||||
@@ -870,13 +947,13 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
err = zw.WriteHeader(header)
|
||||
if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(zw, reader); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
return
|
||||
}
|
||||
@@ -892,17 +969,18 @@ func (s *Server) headHandler(w http.ResponseWriter, r *http.Request) {
|
||||
metadata, err := s.CheckMetadata(token, filename, false)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error metadata: %s", err.Error())
|
||||
s.logger.Printf("Error metadata: %s", err.Error())
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
contentType, contentLength, err := s.storage.Head(token, filename)
|
||||
contentType := metadata.ContentType
|
||||
contentLength, err := s.storage.Head(token, filename)
|
||||
if s.storage.IsNotExist(err) {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
return
|
||||
}
|
||||
@@ -926,17 +1004,18 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
metadata, err := s.CheckMetadata(token, filename, true)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error metadata: %s", err.Error())
|
||||
s.logger.Printf("Error metadata: %s", err.Error())
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
reader, contentType, contentLength, err := s.storage.Get(token, filename)
|
||||
contentType := metadata.ContentType
|
||||
reader, contentLength, err := s.storage.Get(token, filename)
|
||||
if s.storage.IsNotExist(err) {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
return
|
||||
}
|
||||
@@ -960,41 +1039,38 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Remaining-Downloads", remainingDownloads)
|
||||
w.Header().Set("X-Remaining-Days", remainingDays)
|
||||
|
||||
if w.Header().Get("Range") == "" {
|
||||
if _, err = io.Copy(w, reader); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
if disposition == "inline" && canContainsXSS(contentType) {
|
||||
reader = ioutil.NopCloser(bluemonday.UGCPolicy().SanitizeReader(reader))
|
||||
}
|
||||
|
||||
if w.Header().Get("Range") != "" || strings.HasPrefix(metadata.ContentType, "video") || strings.HasPrefix(metadata.ContentType, "audio") {
|
||||
file, err := ioutil.TempFile(s.tempPath, "range-")
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Error occurred copying to output stream", 500)
|
||||
return
|
||||
}
|
||||
|
||||
defer s.cleanTmpFile(file)
|
||||
|
||||
_, err = io.Copy(file, reader)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Error occurred copying to output stream", 500)
|
||||
return
|
||||
}
|
||||
|
||||
http.ServeContent(w, r, filename, time.Now(), file)
|
||||
return
|
||||
}
|
||||
|
||||
file, err := ioutil.TempFile(s.tempPath, "range-")
|
||||
if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
if _, err = io.Copy(w, reader); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Error occurred copying to output stream", 500)
|
||||
return
|
||||
}
|
||||
|
||||
defer cleanTmpFile(file)
|
||||
|
||||
tee := io.TeeReader(reader, file)
|
||||
for {
|
||||
b := make([]byte, _5M)
|
||||
_, err = tee.Read(b)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
http.Error(w, "Error occurred copying to output stream", 500)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
http.ServeContent(w, r, filename, time.Now(), file)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *Server) RedirectHandler(h http.Handler) http.HandlerFunc {
|
||||
@@ -1008,7 +1084,7 @@ func (s *Server) RedirectHandler(h http.Handler) http.HandlerFunc {
|
||||
} else if r.Header.Get("X-Forwarded-Proto") == "https" {
|
||||
} else if r.URL.Scheme == "https" {
|
||||
} else {
|
||||
u := getURL(r)
|
||||
u := getURL(r, s.proxyPort)
|
||||
u.Scheme = "https"
|
||||
|
||||
http.Redirect(w, r, u.String(), http.StatusPermanentRedirect)
|
||||
|
@@ -25,7 +25,10 @@ THE SOFTWARE.
|
||||
package server
|
||||
|
||||
import (
|
||||
crypto_rand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
gorillaHandlers "github.com/gorilla/handlers"
|
||||
"log"
|
||||
"math/rand"
|
||||
"mime"
|
||||
@@ -85,6 +88,13 @@ func Listener(s string) OptionFn {
|
||||
|
||||
}
|
||||
|
||||
func CorsDomains(s string) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.CorsDomains = s
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func GoogleAnalytics(gaKey string) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.gaKey = gaKey
|
||||
@@ -131,6 +141,12 @@ func ProxyPath(s string) OptionFn {
|
||||
}
|
||||
}
|
||||
|
||||
func ProxyPort(s string) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.proxyPort = s
|
||||
}
|
||||
}
|
||||
|
||||
func TempPath(s string) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
if s[len(s)-1:] != "/" {
|
||||
@@ -145,7 +161,7 @@ func LogFile(logger *log.Logger, s string) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
f, err := os.OpenFile(s, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Fatalf("error opening file: %v", err)
|
||||
logger.Fatalf("error opening file: %v", err)
|
||||
}
|
||||
|
||||
logger.SetOutput(f)
|
||||
@@ -159,12 +175,31 @@ func Logger(logger *log.Logger) OptionFn {
|
||||
}
|
||||
}
|
||||
|
||||
func MaxUploadSize(kbytes int64) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.maxUploadSize = kbytes * 1024
|
||||
}
|
||||
|
||||
}
|
||||
func RateLimit(requests int) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.rateLimitRequests = requests
|
||||
}
|
||||
}
|
||||
|
||||
func RandomTokenLength(length int) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.randomTokenLength = length
|
||||
}
|
||||
}
|
||||
|
||||
func Purge(days, interval int) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.purgeDays = time.Duration(days) * time.Hour * 24
|
||||
srvr.purgeInterval = time.Duration(interval) * time.Hour
|
||||
}
|
||||
}
|
||||
|
||||
func ForceHTTPs() OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.forceHTTPs = true
|
||||
@@ -253,14 +288,20 @@ type Server struct {
|
||||
|
||||
profilerEnabled bool
|
||||
|
||||
locks map[string]*sync.Mutex
|
||||
locks sync.Map
|
||||
|
||||
maxUploadSize int64
|
||||
rateLimitRequests int
|
||||
|
||||
purgeDays time.Duration
|
||||
purgeInterval time.Duration
|
||||
|
||||
storage Storage
|
||||
|
||||
forceHTTPs bool
|
||||
|
||||
randomTokenLength int
|
||||
|
||||
ipFilterOptions *IPFilterOptions
|
||||
|
||||
VirusTotalKey string
|
||||
@@ -270,11 +311,13 @@ type Server struct {
|
||||
|
||||
webPath string
|
||||
proxyPath string
|
||||
proxyPort string
|
||||
gaKey string
|
||||
userVoiceKey string
|
||||
|
||||
TLSListenerOnly bool
|
||||
|
||||
CorsDomains string
|
||||
ListenerString string
|
||||
TLSListenerString string
|
||||
ProfileListenerString string
|
||||
@@ -286,7 +329,7 @@ type Server struct {
|
||||
|
||||
func New(options ...OptionFn) (*Server, error) {
|
||||
s := &Server{
|
||||
locks: map[string]*sync.Mutex{},
|
||||
locks: sync.Map{},
|
||||
}
|
||||
|
||||
for _, optionFn := range options {
|
||||
@@ -297,7 +340,11 @@ func New(options ...OptionFn) (*Server, error) {
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
var seedBytes [8]byte
|
||||
if _, err := crypto_rand.Read(seedBytes[:]); err != nil {
|
||||
panic("cannot obtain cryptographically secure seed")
|
||||
}
|
||||
rand.Seed(int64(binary.LittleEndian.Uint64(seedBytes[:])))
|
||||
}
|
||||
|
||||
func (s *Server) Run() {
|
||||
@@ -413,11 +460,24 @@ func (s *Server) Run() {
|
||||
|
||||
s.logger.Printf("Transfer.sh server started.\nusing temp folder: %s\nusing storage provider: %s", s.tempPath, s.storage.Type())
|
||||
|
||||
var cors func(http.Handler) http.Handler
|
||||
if len(s.CorsDomains) > 0 {
|
||||
cors = gorillaHandlers.CORS(
|
||||
gorillaHandlers.AllowedHeaders([]string{"*"}),
|
||||
gorillaHandlers.AllowedOrigins(strings.Split(s.CorsDomains, ",")),
|
||||
gorillaHandlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"}),
|
||||
)
|
||||
} else {
|
||||
cors = func(h http.Handler) http.Handler {
|
||||
return h
|
||||
}
|
||||
}
|
||||
|
||||
h := handlers.PanicHandler(
|
||||
IPFilterHandler(
|
||||
handlers.LogHandler(
|
||||
LoveHandler(
|
||||
s.RedirectHandler(r)),
|
||||
s.RedirectHandler(cors(r))),
|
||||
handlers.NewLogOptions(s.logger.Printf, "_default_"),
|
||||
),
|
||||
s.ipFilterOptions,
|
||||
@@ -458,6 +518,10 @@ func (s *Server) Run() {
|
||||
|
||||
s.logger.Printf("---------------------------")
|
||||
|
||||
if s.purgeDays > 0 {
|
||||
go s.purgeHandler()
|
||||
}
|
||||
|
||||
term := make(chan os.Signal, 1)
|
||||
signal.Notify(term, os.Interrupt)
|
||||
signal.Notify(term, syscall.SIGTERM)
|
||||
|
@@ -1,90 +0,0 @@
|
||||
// +build gofuzz
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const applicationOctetStream = "application/octet-stream"
|
||||
|
||||
// FuzzLocalStorage tests the Local Storage.
|
||||
func FuzzLocalStorage(fuzz []byte) int {
|
||||
var fuzzLength = uint64(len(fuzz))
|
||||
if fuzzLength == 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
storage, err := NewLocalStorage("/tmp", nil)
|
||||
if err != nil {
|
||||
panic("unable to create local storage")
|
||||
}
|
||||
|
||||
token := Encode(10000000 + int64(rand.Intn(1000000000)))
|
||||
filename := Encode(10000000 + int64(rand.Intn(1000000000))) + ".bin"
|
||||
|
||||
input := bytes.NewReader(fuzz)
|
||||
err = storage.Put(token, filename, input, applicationOctetStream, fuzzLength)
|
||||
if err != nil {
|
||||
panic("unable to save file")
|
||||
}
|
||||
|
||||
contentType, contentLength, err := storage.Head(token, filename)
|
||||
if err != nil {
|
||||
panic("not visible through head")
|
||||
}
|
||||
|
||||
if contentType != applicationOctetStream {
|
||||
panic("incorrect content type")
|
||||
}
|
||||
|
||||
if contentLength != fuzzLength {
|
||||
panic("incorrect content length")
|
||||
}
|
||||
|
||||
output, contentType, contentLength, err := storage.Get(token, filename)
|
||||
if err != nil {
|
||||
panic("not visible through get")
|
||||
}
|
||||
|
||||
if contentType != applicationOctetStream {
|
||||
panic("incorrect content type")
|
||||
}
|
||||
|
||||
if contentLength != fuzzLength {
|
||||
panic("incorrect content length")
|
||||
}
|
||||
|
||||
var length uint64
|
||||
b := make([]byte, len(fuzz))
|
||||
for {
|
||||
n, err := output.Read(b)
|
||||
length += uint64(n)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(b, fuzz) {
|
||||
panic("incorrect content body")
|
||||
}
|
||||
|
||||
if length != fuzzLength {
|
||||
panic("incorrect content length")
|
||||
}
|
||||
|
||||
err = storage.Delete(token, filename)
|
||||
if err != nil {
|
||||
panic("unable to delete file")
|
||||
}
|
||||
|
||||
_, _, err = storage.Head(token, filename)
|
||||
if !storage.IsNotExist(err) {
|
||||
panic("file not deleted")
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
@@ -2,16 +2,8 @@ package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"mime"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
@@ -22,14 +14,26 @@ import (
|
||||
"golang.org/x/oauth2/google"
|
||||
"google.golang.org/api/drive/v3"
|
||||
"google.golang.org/api/googleapi"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"storj.io/common/storj"
|
||||
"storj.io/uplink"
|
||||
)
|
||||
|
||||
type Storage interface {
|
||||
Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error)
|
||||
Head(token string, filename string) (contentType string, contentLength uint64, err error)
|
||||
Get(token string, filename string) (reader io.ReadCloser, contentLength uint64, err error)
|
||||
Head(token string, filename string) (contentLength uint64, err error)
|
||||
Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) error
|
||||
Delete(token string, filename string) error
|
||||
IsNotExist(err error) bool
|
||||
Purge(days time.Duration) error
|
||||
|
||||
Type() string
|
||||
}
|
||||
@@ -48,7 +52,7 @@ func (s *LocalStorage) Type() string {
|
||||
return "local"
|
||||
}
|
||||
|
||||
func (s *LocalStorage) Head(token string, filename string) (contentType string, contentLength uint64, err error) {
|
||||
func (s *LocalStorage) Head(token string, filename string) (contentLength uint64, err error) {
|
||||
path := filepath.Join(s.basedir, token, filename)
|
||||
|
||||
var fi os.FileInfo
|
||||
@@ -58,12 +62,10 @@ func (s *LocalStorage) Head(token string, filename string) (contentType string,
|
||||
|
||||
contentLength = uint64(fi.Size())
|
||||
|
||||
contentType = mime.TypeByExtension(filepath.Ext(filename))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *LocalStorage) Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error) {
|
||||
func (s *LocalStorage) Get(token string, filename string) (reader io.ReadCloser, contentLength uint64, err error) {
|
||||
path := filepath.Join(s.basedir, token, filename)
|
||||
|
||||
// content type , content length
|
||||
@@ -78,8 +80,6 @@ func (s *LocalStorage) Get(token string, filename string) (reader io.ReadCloser,
|
||||
|
||||
contentLength = uint64(fi.Size())
|
||||
|
||||
contentType = mime.TypeByExtension(filepath.Ext(filename))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -92,6 +92,27 @@ func (s *LocalStorage) Delete(token string, filename string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *LocalStorage) Purge(days time.Duration) (err error) {
|
||||
err = filepath.Walk(s.basedir,
|
||||
func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if info.ModTime().Before(time.Now().Add(-1 * days)) {
|
||||
err = os.Remove(path)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *LocalStorage) IsNotExist(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
@@ -129,20 +150,28 @@ type S3Storage struct {
|
||||
session *session.Session
|
||||
s3 *s3.S3
|
||||
logger *log.Logger
|
||||
purgeDays time.Duration
|
||||
noMultipart bool
|
||||
}
|
||||
|
||||
func NewS3Storage(accessKey, secretKey, bucketName, region, endpoint string, logger *log.Logger, disableMultipart bool, forcePathStyle bool) (*S3Storage, error) {
|
||||
func NewS3Storage(accessKey, secretKey, bucketName string, purgeDays int, region, endpoint string, disableMultipart bool, forcePathStyle bool, logger *log.Logger) (*S3Storage, error) {
|
||||
sess := getAwsSession(accessKey, secretKey, region, endpoint, forcePathStyle)
|
||||
|
||||
return &S3Storage{bucket: bucketName, s3: s3.New(sess), session: sess, logger: logger, noMultipart: disableMultipart}, nil
|
||||
return &S3Storage{
|
||||
bucket: bucketName,
|
||||
s3: s3.New(sess),
|
||||
session: sess,
|
||||
logger: logger,
|
||||
noMultipart: disableMultipart,
|
||||
purgeDays: time.Duration(purgeDays*24) * time.Hour,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *S3Storage) Type() string {
|
||||
return "s3"
|
||||
}
|
||||
|
||||
func (s *S3Storage) Head(token string, filename string) (contentType string, contentLength uint64, err error) {
|
||||
func (s *S3Storage) Head(token string, filename string) (contentLength uint64, err error) {
|
||||
key := fmt.Sprintf("%s/%s", token, filename)
|
||||
|
||||
headRequest := &s3.HeadObjectInput{
|
||||
@@ -156,10 +185,6 @@ func (s *S3Storage) Head(token string, filename string) (contentType string, con
|
||||
return
|
||||
}
|
||||
|
||||
if response.ContentType != nil {
|
||||
contentType = *response.ContentType
|
||||
}
|
||||
|
||||
if response.ContentLength != nil {
|
||||
contentLength = uint64(*response.ContentLength)
|
||||
}
|
||||
@@ -167,6 +192,11 @@ func (s *S3Storage) Head(token string, filename string) (contentType string, con
|
||||
return
|
||||
}
|
||||
|
||||
func (s *S3Storage) Purge(days time.Duration) (err error) {
|
||||
// NOOP expiration is set at upload time
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *S3Storage) IsNotExist(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
@@ -182,7 +212,7 @@ func (s *S3Storage) IsNotExist(err error) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *S3Storage) Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error) {
|
||||
func (s *S3Storage) Get(token string, filename string) (reader io.ReadCloser, contentLength uint64, err error) {
|
||||
key := fmt.Sprintf("%s/%s", token, filename)
|
||||
|
||||
getRequest := &s3.GetObjectInput{
|
||||
@@ -195,10 +225,6 @@ func (s *S3Storage) Get(token string, filename string) (reader io.ReadCloser, co
|
||||
return
|
||||
}
|
||||
|
||||
if response.ContentType != nil {
|
||||
contentType = *response.ContentType
|
||||
}
|
||||
|
||||
if response.ContentLength != nil {
|
||||
contentLength = uint64(*response.ContentLength)
|
||||
}
|
||||
@@ -247,10 +273,16 @@ func (s *S3Storage) Put(token string, filename string, reader io.Reader, content
|
||||
u.LeavePartsOnError = false
|
||||
})
|
||||
|
||||
var expire *time.Time
|
||||
if s.purgeDays.Hours() > 0 {
|
||||
expire = aws.Time(time.Now().Add(s.purgeDays))
|
||||
}
|
||||
|
||||
_, err = uploader.Upload(&s3manager.UploadInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
Body: reader,
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(key),
|
||||
Body: reader,
|
||||
Expires: expire,
|
||||
})
|
||||
|
||||
return
|
||||
@@ -398,7 +430,7 @@ func (s *GDrive) Type() string {
|
||||
return "gdrive"
|
||||
}
|
||||
|
||||
func (s *GDrive) Head(token string, filename string) (contentType string, contentLength uint64, err error) {
|
||||
func (s *GDrive) Head(token string, filename string) (contentLength uint64, err error) {
|
||||
var fileId string
|
||||
fileId, err = s.findId(filename, token)
|
||||
if err != nil {
|
||||
@@ -406,18 +438,16 @@ func (s *GDrive) Head(token string, filename string) (contentType string, conten
|
||||
}
|
||||
|
||||
var fi *drive.File
|
||||
if fi, err = s.service.Files.Get(fileId).Fields("mimeType", "size").Do(); err != nil {
|
||||
if fi, err = s.service.Files.Get(fileId).Fields("size").Do(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
contentLength = uint64(fi.Size)
|
||||
|
||||
contentType = fi.MimeType
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *GDrive) Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error) {
|
||||
func (s *GDrive) Get(token string, filename string) (reader io.ReadCloser, contentLength uint64, err error) {
|
||||
var fileId string
|
||||
fileId, err = s.findId(filename, token)
|
||||
if err != nil {
|
||||
@@ -425,14 +455,13 @@ func (s *GDrive) Get(token string, filename string) (reader io.ReadCloser, conte
|
||||
}
|
||||
|
||||
var fi *drive.File
|
||||
fi, err = s.service.Files.Get(fileId).Fields("mimeType", "size", "md5Checksum").Do()
|
||||
fi, err = s.service.Files.Get(fileId).Fields("size", "md5Checksum").Do()
|
||||
if !s.hasChecksum(fi) {
|
||||
err = fmt.Errorf("Cannot find file %s/%s", token, filename)
|
||||
return
|
||||
}
|
||||
|
||||
contentLength = uint64(fi.Size)
|
||||
contentType = fi.MimeType
|
||||
|
||||
ctx := context.Background()
|
||||
var res *http.Response
|
||||
@@ -460,6 +489,34 @@ func (s *GDrive) Delete(token string, filename string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (s *GDrive) Purge(days time.Duration) (err error) {
|
||||
nextPageToken := ""
|
||||
|
||||
expirationDate := time.Now().Add(-1 * days).Format(time.RFC3339)
|
||||
q := fmt.Sprintf("'%s' in parents and modifiedTime < '%s' and mimeType!='%s' and trashed=false", s.rootId, expirationDate, GDriveDirectoryMimeType)
|
||||
l, err := s.list(nextPageToken, q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for 0 < len(l.Files) {
|
||||
for _, fi := range l.Files {
|
||||
err = s.service.Files.Delete(fi.Id).Do()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if l.NextPageToken == "" {
|
||||
break
|
||||
}
|
||||
|
||||
l, err = s.list(l.NextPageToken, q)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *GDrive) IsNotExist(err error) bool {
|
||||
if err != nil {
|
||||
if e, ok := err.(*googleapi.Error); ok {
|
||||
@@ -561,3 +618,133 @@ func saveGDriveToken(path string, token *oauth2.Token, logger *log.Logger) {
|
||||
|
||||
json.NewEncoder(f).Encode(token)
|
||||
}
|
||||
|
||||
type StorjStorage struct {
|
||||
Storage
|
||||
project *uplink.Project
|
||||
bucket *uplink.Bucket
|
||||
purgeDays time.Duration
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func NewStorjStorage(access, bucket string, purgeDays int, logger *log.Logger) (*StorjStorage, error) {
|
||||
var instance StorjStorage
|
||||
var err error
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
parsedAccess, err := uplink.ParseAccess(access)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instance.project, err = uplink.OpenProject(ctx, parsedAccess)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instance.bucket, err = instance.project.EnsureBucket(ctx, bucket)
|
||||
if err != nil {
|
||||
//Ignoring the error to return the one that occurred first, but try to clean up.
|
||||
_ = instance.project.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instance.purgeDays = time.Duration(purgeDays*24) * time.Hour
|
||||
|
||||
instance.logger = logger
|
||||
|
||||
return &instance, nil
|
||||
}
|
||||
|
||||
func (s *StorjStorage) Type() string {
|
||||
return "storj"
|
||||
}
|
||||
|
||||
func (s *StorjStorage) Head(token string, filename string) (contentLength uint64, err error) {
|
||||
key := storj.JoinPaths(token, filename)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
obj, err := s.project.StatObject(ctx, s.bucket.Name, key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
contentLength = uint64(obj.System.ContentLength)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *StorjStorage) Get(token string, filename string) (reader io.ReadCloser, contentLength uint64, err error) {
|
||||
key := storj.JoinPaths(token, filename)
|
||||
|
||||
s.logger.Printf("Getting file %s from Storj Bucket", filename)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
download, err := s.project.DownloadObject(ctx, s.bucket.Name, key, nil)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
contentLength = uint64(download.Info().System.ContentLength)
|
||||
|
||||
reader = download
|
||||
return
|
||||
}
|
||||
|
||||
func (s *StorjStorage) Delete(token string, filename string) (err error) {
|
||||
key := storj.JoinPaths(token, filename)
|
||||
|
||||
s.logger.Printf("Deleting file %s from Storj Bucket", filename)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
_, err = s.project.DeleteObject(ctx, s.bucket.Name, key)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *StorjStorage) Purge(days time.Duration) (err error) {
|
||||
// NOOP expiration is set at upload time
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StorjStorage) Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) (err error) {
|
||||
key := storj.JoinPaths(token, filename)
|
||||
|
||||
s.logger.Printf("Uploading file %s to Storj Bucket", filename)
|
||||
|
||||
ctx := context.TODO()
|
||||
|
||||
var uploadOptions *uplink.UploadOptions
|
||||
if s.purgeDays.Hours() > 0 {
|
||||
uploadOptions = &uplink.UploadOptions{Expires: time.Now().Add(s.purgeDays)}
|
||||
}
|
||||
|
||||
writer, err := s.project.UploadObject(ctx, s.bucket.Name, key, uploadOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := io.Copy(writer, reader)
|
||||
if err != nil || uint64(n) != contentLength {
|
||||
//Ignoring the error to return the one that occurred first, but try to clean up.
|
||||
_ = writer.Abort()
|
||||
return err
|
||||
}
|
||||
err = writer.SetCustomMetadata(ctx, uplink.CustomMetadata{"content-type": contentType})
|
||||
if err != nil {
|
||||
//Ignoring the error to return the one that occurred first, but try to clean up.
|
||||
_ = writer.Abort()
|
||||
return err
|
||||
}
|
||||
|
||||
err = writer.Commit()
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StorjStorage) IsNotExist(err error) bool {
|
||||
return errors.Is(err, uplink.ErrObjectNotFound)
|
||||
}
|
||||
|
45
server/token.go
Normal file
45
server/token.go
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020- Andrea Spacca and Stefan Benten.
|
||||
|
||||
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 server
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
const (
|
||||
// characters used for short-urls
|
||||
SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
)
|
||||
|
||||
// generate a token
|
||||
func Token(length int) string {
|
||||
result := ""
|
||||
for i := 0; i < length; i++ {
|
||||
x := rand.Intn(len(SYMBOLS) - 1)
|
||||
result = string(SYMBOLS[x]) + result
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
15
server/token_test.go
Normal file
15
server/token_test.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package server
|
||||
|
||||
import "testing"
|
||||
|
||||
func BenchmarkTokenConcat(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = Token(5) + Token(5)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTokenLonger(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = Token(10)
|
||||
}
|
||||
}
|
@@ -2,6 +2,8 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2017 DutchCoders [https://github.com/dutchcoders/]
|
||||
Copyright (c) 2018-2020 Andrea Spacca.
|
||||
Copyright (c) 2020- Andrea Spacca and Stefan Benten.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -25,6 +27,7 @@ THE SOFTWARE.
|
||||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/mail"
|
||||
@@ -47,7 +50,6 @@ func getAwsSession(accessKey, secretKey, region, endpoint string, forcePathStyle
|
||||
}
|
||||
|
||||
func formatNumber(format string, s uint64) string {
|
||||
|
||||
return RenderFloat(format, float64(s))
|
||||
}
|
||||
|
||||
@@ -253,3 +255,27 @@ func acceptsHTML(hdr http.Header) bool {
|
||||
|
||||
return (false)
|
||||
}
|
||||
|
||||
func formatSize(size int64) string {
|
||||
sizeFloat := float64(size)
|
||||
base := math.Log(sizeFloat) / math.Log(1024)
|
||||
|
||||
sizeOn := math.Pow(1024, base-math.Floor(base))
|
||||
|
||||
var round float64
|
||||
pow := math.Pow(10, float64(2))
|
||||
digit := pow * sizeOn
|
||||
round = math.Floor(digit)
|
||||
|
||||
newVal := round / pow
|
||||
|
||||
var suffixes [5]string
|
||||
suffixes[0] = "B"
|
||||
suffixes[1] = "KB"
|
||||
suffixes[2] = "MB"
|
||||
suffixes[3] = "GB"
|
||||
suffixes[4] = "TB"
|
||||
|
||||
getSuffix := suffixes[int(math.Floor(base))]
|
||||
return fmt.Sprintf("%s %s", strconv.FormatFloat(newVal, 'f', -1, 64), getSuffix)
|
||||
}
|
||||
|
Reference in New Issue
Block a user