Compare commits
8 Commits
clamav-pre
...
gpg-encryp
Author | SHA1 | Date | |
---|---|---|---|
|
a7b600c562 | ||
|
715f2b4cd9 | ||
|
597554a59e | ||
|
368431fb6b | ||
|
e3bb49993c | ||
|
cff0a88bf3 | ||
|
fbf9a4facc | ||
|
0c844c1f11 |
@@ -6,6 +6,7 @@ bin
|
||||
*.pyc
|
||||
*.egg-info
|
||||
.vagrant
|
||||
.git
|
||||
.tmp
|
||||
bower_components
|
||||
node_modules
|
||||
|
@@ -18,3 +18,7 @@ issues:
|
||||
max-same-issues: 0
|
||||
new: false
|
||||
exclude-use-default: false
|
||||
exclude-rules:
|
||||
- linters:
|
||||
- staticcheck
|
||||
text: "SA1019:"
|
||||
|
5
Makefile
Normal file
5
Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
.PHONY: lint
|
||||
|
||||
lint:
|
||||
golangci-lint run --out-format=github-actions --config .golangci.yml
|
||||
|
11
README.md
11
README.md
@@ -47,6 +47,16 @@ $ curl --upload-file ./hello.txt https://transfer.sh/hello.txt -H "Max-Downloads
|
||||
$ curl --upload-file ./hello.txt https://transfer.sh/hello.txt -H "Max-Days: 1" # Set the number of days before deletion
|
||||
```
|
||||
|
||||
### X-Encrypt-Password
|
||||
```bash
|
||||
$ curl --upload-file ./hello.txt https://transfer.sh/hello.txt -H "X-Encrypt-Password: test" # Encrypt the content sever side with AES265 using "test" as password
|
||||
```
|
||||
|
||||
### X-Decrypt-Password
|
||||
```bash
|
||||
$ curl https://transfer.sh/BAYh0/hello.txt -H "X-Decrypt-Password: test" # Decrypt the content sever side with AES265 using "test" as password
|
||||
```
|
||||
|
||||
## Response Headers
|
||||
|
||||
### X-Url-Delete
|
||||
@@ -111,6 +121,7 @@ lets-encrypt-hosts | hosts to use for lets encrypt certificates (comma seperated
|
||||
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 |
|
||||
perform-clamav-prescan | prescan every upload through clamav feature (clamav-host must be a local clamd unix socket) | | PERFORM_CLAMAV_PRESCAN |
|
||||
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 |
|
||||
|
13
cmd/cmd.go
13
cmd/cmd.go
@@ -240,6 +240,11 @@ var globalFlags = []cli.Flag{
|
||||
Value: "",
|
||||
EnvVar: "CLAMAV_HOST",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "perform-clamav-prescan",
|
||||
Usage: "perform-clamav-prescan",
|
||||
EnvVar: "PERFORM_CLAMAV_PRESCAN",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "virustotal-key",
|
||||
Usage: "virustotal-key",
|
||||
@@ -388,6 +393,14 @@ func New() *Cmd {
|
||||
options = append(options, server.ClamavHost(v))
|
||||
}
|
||||
|
||||
if v := c.Bool("perform-clamav-prescan"); v {
|
||||
if c.String("clamav-host") == "" {
|
||||
panic("clamav-host not set")
|
||||
}
|
||||
|
||||
options = append(options, server.PerformClamavPrescan(v))
|
||||
}
|
||||
|
||||
if v := c.Int64("max-upload-size"); v > 0 {
|
||||
options = append(options, server.MaxUploadSize(v))
|
||||
}
|
||||
|
6
go.mod
6
go.mod
@@ -25,12 +25,12 @@ require (
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
||||
github.com/urfave/cli v1.22.5
|
||||
go.opencensus.io v0.22.6 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
|
||||
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-20211102144601-401a79f0706a
|
||||
storj.io/uplink v1.7.1
|
||||
storj.io/common v0.0.0-20220131120956-e74f624a3d55
|
||||
storj.io/uplink v1.7.2-0.20220131124001-c1db742c840d
|
||||
)
|
||||
|
49
go.sum
49
go.sum
@@ -49,7 +49,6 @@ github.com/PuerkitoBio/ghost v0.0.0-20160324114900-206e6e460e14 h1:3zOOc7WdrATDX
|
||||
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/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
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=
|
||||
@@ -58,16 +57,6 @@ github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd3
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
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/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/calebcase/tmpfile v1.0.3 h1:BZrOWZ79gJqQ3XbAQlihYZf/YCV0H4KPIdM5K5oMpJo=
|
||||
github.com/calebcase/tmpfile v1.0.3/go.mod h1:UAUc01aHeC+pudPagY/lWvt2qS9ZO5Zzof6/tIUzqeI=
|
||||
@@ -85,7 +74,6 @@ github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7
|
||||
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=
|
||||
@@ -193,8 +181,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
||||
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/pprof v0.0.0-20211008130755-947d60d73cc0 h1:zHs+jv3LO743/zFGcByu2KmpbliCU2AhjcGgrdTwSG4=
|
||||
github.com/google/pprof v0.0.0-20211008130755-947d60d73cc0/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/pprof v0.0.0-20211108044417-e9b028704de0 h1:rsq1yB2xiFLDYYaYdlGBsSkwVzsCo500wMhxvW5A/bk=
|
||||
github.com/google/pprof v0.0.0-20211108044417-e9b028704de0/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
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=
|
||||
@@ -224,19 +212,16 @@ github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||
github.com/inconshreveable/log15 v0.0.0-20170622235902-74a0988b5f80/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
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/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
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=
|
||||
@@ -272,12 +257,10 @@ github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
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/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
@@ -328,7 +311,6 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDq
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.4/go.mod h1:JcK1pCbReQsOsMKF/POFSZCq7drXFybgGmbc27tuwes=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.12/go.mod h1:kj1ViJhlyADa7DiA4xVnTuPA46lFKbM7mxQTrXCuJP4=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.17 h1:rqIuLhRUr2UtS3WNVbPY/BwvjlwKVvSOVY5p0QVocxE=
|
||||
github.com/spacemonkeygo/monkit/v3 v3.0.17/go.mod h1:kj1ViJhlyADa7DiA4xVnTuPA46lFKbM7mxQTrXCuJP4=
|
||||
github.com/spacemonkeygo/monotime v0.0.0-20180824235756-e3f48a95f98a/go.mod h1:ul4bvvnCOPZgq8w0nTkSmWVg/hauVpFS97Am1YM1XXo=
|
||||
@@ -358,7 +340,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zeebo/admission/v3 v3.0.2/go.mod h1:BP3isIv9qa2A7ugEratNq1dnl2oZRXaQUGdU7WXKtbw=
|
||||
github.com/zeebo/admission/v3 v3.0.3/go.mod h1:2OWyAS5yo0Xvj2AEUosOjTUHxaY0oIIiCrXGKCYzWpo=
|
||||
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=
|
||||
@@ -376,18 +358,16 @@ go.opencensus.io v0.22.6 h1:BdkrbWrzDlV9dnbzoP7sfN+dHheJ4J9JOaYxcUDL+ok=
|
||||
go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/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-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
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-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
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=
|
||||
@@ -541,8 +521,8 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211020064051-0ec99a608a1b h1:byBDhtWGQmWDrv1MlEv/BzGRMkw36h9QqsNnZQcDhRw=
|
||||
golang.org/x/sys v0.0.0-20211020064051-0ec99a608a1b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211109065445-02f5c0300f6e h1:i6Vklmyu+fZMFYpum+sR4ZWABGW7MyIxfJZXYvcnbns=
|
||||
golang.org/x/sys v0.0.0-20211109065445-02f5c0300f6e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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=
|
||||
@@ -724,8 +704,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
@@ -757,9 +738,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
storj.io/common v0.0.0-20211102144601-401a79f0706a h1:6AF6LcFbZ8PtQX6omT6npU8Yhh1g7OG2emZKuLgS5+o=
|
||||
storj.io/common v0.0.0-20211102144601-401a79f0706a/go.mod h1:a2Kw7Uipu929OFANfWKLHRoD0JfhgssikEvimd6hbSQ=
|
||||
storj.io/drpc v0.0.26 h1:T6jJzjby7QUa/2XHR1qMxTCENpDHEw4/o+kfDfZQqQI=
|
||||
storj.io/drpc v0.0.26/go.mod h1:ofQUDPQbbIymRDKE0tms48k8bLP5Y+dsI9CbXGv3gko=
|
||||
storj.io/uplink v1.7.1 h1:W40Gp9VFda4/6Vbt2HziNPGJd47t7ELanDNfZKsriNY=
|
||||
storj.io/uplink v1.7.1/go.mod h1:pKqsMpNMIAz//2TXzUGOR6tpu3iyabvXV4VWINj4jaY=
|
||||
storj.io/common v0.0.0-20220131120956-e74f624a3d55 h1:HgFcPy1vohRJ4VRRGej92N31i5znL1KGWhDVgGgjBG4=
|
||||
storj.io/common v0.0.0-20220131120956-e74f624a3d55/go.mod h1:m0489td5+rKDdoiYOzCkh3CfGW/cLyntZiYfso+QfMs=
|
||||
storj.io/drpc v0.0.29 h1:Ihd4ls/JQFr0lctefie3iu+3QM4duccCKr9uMzf4sKY=
|
||||
storj.io/drpc v0.0.29/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
|
||||
storj.io/uplink v1.7.2-0.20220131124001-c1db742c840d h1:Fb9Tht/h8KJbn02obTM1mseR4b7WQ7PCf+Nc3wXC3vk=
|
||||
storj.io/uplink v1.7.2-0.20220131124001-c1db742c840d/go.mod h1:BYnzl+ordVACxbWM7eKUvkqC+GvSnMmVbIyA2BNGBmk=
|
||||
|
@@ -27,18 +27,19 @@ THE SOFTWARE.
|
||||
package server
|
||||
|
||||
import (
|
||||
// _ "transfer.sh/app/handlers"
|
||||
// _ "transfer.sh/app/utils"
|
||||
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
clamd "github.com/dutchcoders/go-clamd"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
const clamavScanStatusOK = "OK"
|
||||
|
||||
func (s *Server) scanHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
@@ -49,23 +50,53 @@ func (s *Server) scanHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
s.logger.Printf("Scanning %s %d %s", filename, contentLength, contentType)
|
||||
|
||||
reader := r.Body
|
||||
|
||||
c := clamd.NewClamd(s.ClamAVDaemonHost)
|
||||
|
||||
abort := make(chan bool)
|
||||
defer close(abort)
|
||||
response, err := c.ScanStream(reader, abort)
|
||||
file, err := ioutil.TempFile(s.tempPath, "clamav-")
|
||||
defer s.cleanTmpFile(file)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = io.Copy(file, r.Body)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
status, err := s.performScan(file.Name())
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("%v\n", status)))
|
||||
}
|
||||
|
||||
func (s *Server) performScan(path string) (string, error) {
|
||||
c := clamd.NewClamd(s.ClamAVDaemonHost)
|
||||
|
||||
responseCh := make(chan chan *clamd.ScanResult)
|
||||
errCh := make(chan error)
|
||||
go func(responseCh chan chan *clamd.ScanResult, errCh chan error) {
|
||||
response, err := c.ScanFile(path)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
responseCh <- response
|
||||
}(responseCh, errCh)
|
||||
|
||||
select {
|
||||
case s := <-response:
|
||||
_, _ = w.Write([]byte(fmt.Sprintf("%v\n", s.Status)))
|
||||
case err := <-errCh:
|
||||
return "", err
|
||||
case response := <-responseCh:
|
||||
st := <-response
|
||||
return st.Status, nil
|
||||
case <-time.After(time.Second * 60):
|
||||
abort <- true
|
||||
return "", errors.New("clamav scan timeout")
|
||||
}
|
||||
}
|
||||
|
@@ -58,6 +58,12 @@ import (
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
blackfriday "github.com/russross/blackfriday/v2"
|
||||
"github.com/skip2/go-qrcode"
|
||||
//lint:ignore SA1019 Ignore the deprecation warnings
|
||||
"golang.org/x/crypto/openpgp"
|
||||
//lint:ignore SA1019 Ignore the deprecation warnings
|
||||
"golang.org/x/crypto/openpgp/armor"
|
||||
//lint:ignore SA1019 Ignore the deprecation warnings
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
)
|
||||
|
||||
const getPathPart = "get"
|
||||
@@ -65,6 +71,10 @@ const getPathPart = "get"
|
||||
var (
|
||||
htmlTemplates = initHTMLTemplates()
|
||||
textTemplates = initTextTemplates()
|
||||
|
||||
packetConfig = &packet.Config{
|
||||
DefaultCipher: packet.CipherAES256,
|
||||
}
|
||||
)
|
||||
|
||||
func stripPrefix(path string) string {
|
||||
@@ -88,6 +98,96 @@ func initHTMLTemplates() *html_template.Template {
|
||||
return templates
|
||||
}
|
||||
|
||||
func transformEncryptionReader(reader io.ReadCloser, password string) (io.Reader, error) {
|
||||
if len(password) == 0 {
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
return encrypt(reader, password, packetConfig)
|
||||
}
|
||||
|
||||
func transformDecryptionReader(reader io.ReadCloser, password string) (io.Reader, error) {
|
||||
if len(password) == 0 {
|
||||
return reader, nil
|
||||
}
|
||||
|
||||
return decrypt(reader, password, packetConfig)
|
||||
}
|
||||
|
||||
func decrypt(ciphertext io.ReadCloser, password string, packetConfig *packet.Config) (plaintext io.Reader, err error) {
|
||||
content, err := ioutil.ReadAll(ciphertext)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
decbuf := bytes.NewBuffer(content)
|
||||
|
||||
armorBlock, err := armor.Decode(decbuf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
failed := false
|
||||
prompt := func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
|
||||
// If the given passphrase isn't correct, the function will be called again, forever.
|
||||
// This method will fail fast.
|
||||
// Ref: https://godoc.org/golang.org/x/crypto/openpgp#PromptFunction
|
||||
if failed {
|
||||
return nil, errors.New("decryption failed")
|
||||
}
|
||||
failed = true
|
||||
return []byte(password), nil
|
||||
}
|
||||
|
||||
md, err := openpgp.ReadMessage(armorBlock.Body, nil, prompt, packetConfig)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
plaintext = md.UnverifiedBody
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func encrypt(plaintext io.ReadCloser, password string, packetConfig *packet.Config) (ciphertext io.Reader, err error) {
|
||||
encbuf := bytes.NewBuffer(nil)
|
||||
|
||||
w, err := armor.Encode(encbuf, "PGP MESSAGE", nil)
|
||||
if err != nil {
|
||||
safeClose(w)
|
||||
return
|
||||
}
|
||||
|
||||
pt, err := openpgp.SymmetricallyEncrypt(w, []byte(password), nil, packetConfig)
|
||||
|
||||
if err != nil {
|
||||
safeClose(pt)
|
||||
safeClose(w)
|
||||
return
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadAll(plaintext)
|
||||
if err != nil {
|
||||
safeClose(pt)
|
||||
safeClose(w)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = pt.Write(content)
|
||||
if err != nil {
|
||||
safeClose(pt)
|
||||
safeClose(w)
|
||||
return
|
||||
}
|
||||
|
||||
// Close writers to force-flush their buffer
|
||||
safeClose(pt)
|
||||
safeClose(w)
|
||||
ciphertext = bytes.NewReader(encbuf.Bytes())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte("Approaching Neutral Zone, all systems normal and functioning."))
|
||||
}
|
||||
@@ -291,7 +391,7 @@ func sanitize(fileName string) string {
|
||||
func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseMultipartForm(_24K); nil != err {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Error occurred copying to output stream", 500)
|
||||
http.Error(w, "Error occurred copying to output stream", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -299,6 +399,8 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
|
||||
responseBody := ""
|
||||
|
||||
for _, fheaders := range r.MultipartForm.File {
|
||||
for _, fheader := range fheaders {
|
||||
filename := sanitize(fheader.Filename)
|
||||
@@ -309,83 +411,97 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if f, err = fheader.Open(); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
file, err := ioutil.TempFile(s.tempPath, "transfer-")
|
||||
defer s.cleanTmpFile(file)
|
||||
|
||||
n, err := io.CopyN(&b, f, _24K+1)
|
||||
if err != nil && err != io.EOF {
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var file *os.File
|
||||
var reader io.Reader
|
||||
|
||||
if n > _24K {
|
||||
file, err = ioutil.TempFile(s.tempPath, "transfer-")
|
||||
defer s.cleanTmpFile(file)
|
||||
if err != nil {
|
||||
s.logger.Fatal(err)
|
||||
}
|
||||
|
||||
n, err = io.Copy(file, io.MultiReader(&b, f))
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
reader, err = os.Open(file.Name())
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
reader = bytes.NewReader(b.Bytes())
|
||||
n, err := io.Copy(file, f)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
contentLength := n
|
||||
|
||||
_, err = file.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if s.maxUploadSize > 0 && contentLength > s.maxUploadSize {
|
||||
s.logger.Print("Entity too large")
|
||||
http.Error(w, http.StatusText(http.StatusRequestEntityTooLarge), http.StatusRequestEntityTooLarge)
|
||||
return
|
||||
}
|
||||
|
||||
metadata := metadataForRequest(contentType, s.randomTokenLength, r)
|
||||
if s.performClamavPrescan {
|
||||
status, err := s.performScan(file.Name())
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not perform prescan", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if status != clamavScanStatusOK {
|
||||
s.logger.Printf("prescan positive: %s", status)
|
||||
http.Error(w, "Clamav prescan found a virus", http.StatusPreconditionFailed)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
metadata := metadataForRequest(contentType, contentLength, s.randomTokenLength, r)
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not encode metadata", 500)
|
||||
http.Error(w, "Could not encode metadata", http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
} else if err := s.storage.Put(r.Context(), token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not save metadata", 500)
|
||||
http.Error(w, "Could not save metadata", http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s.logger.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
|
||||
|
||||
reader, err := transformEncryptionReader(file, r.Header.Get("X-Encrypt-Password"))
|
||||
if err != nil {
|
||||
http.Error(w, "Could not crypt file", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.storage.Put(r.Context(), token, filename, reader, contentType, uint64(contentLength)); err != nil {
|
||||
s.logger.Printf("Backend storage error: %s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
filename = url.PathEscape(filename)
|
||||
relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
|
||||
_, _ = w.Write([]byte(getURL(r, s.proxyPort).ResolveReference(relativeURL).String()))
|
||||
deleteURL, _ := url.Parse(path.Join(s.proxyPath, token, filename, metadata.DeletionToken))
|
||||
w.Header().Add("X-Url-Delete", resolveURL(r, deleteURL, s.proxyPort))
|
||||
responseBody += fmt.Sprintln(getURL(r, s.proxyPort).ResolveReference(relativeURL).String())
|
||||
}
|
||||
}
|
||||
_, err := w.Write([]byte(responseBody))
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) cleanTmpFile(f *os.File) {
|
||||
@@ -405,8 +521,8 @@ func (s *Server) cleanTmpFile(f *os.File) {
|
||||
type metadata struct {
|
||||
// ContentType is the original uploading content type
|
||||
ContentType string
|
||||
// Secret as knowledge to delete file
|
||||
// Secret string
|
||||
// ContentLength is is the original uploading content length
|
||||
ContentLength int64
|
||||
// Downloads is the actual number of downloads
|
||||
Downloads int
|
||||
// MaxDownloads contains the maximum numbers of downloads
|
||||
@@ -415,11 +531,16 @@ type metadata struct {
|
||||
MaxDate time.Time
|
||||
// DeletionToken contains the token to match against for deletion
|
||||
DeletionToken string
|
||||
// Encrypted contains if the file was encrypted
|
||||
Encrypted bool
|
||||
// DecryptedContentType is the original uploading content type
|
||||
DecryptedContentType string
|
||||
}
|
||||
|
||||
func metadataForRequest(contentType string, randomTokenLength int, r *http.Request) metadata {
|
||||
func metadataForRequest(contentType string, contentLength int64, randomTokenLength int, r *http.Request) metadata {
|
||||
metadata := metadata{
|
||||
ContentType: strings.ToLower(contentType),
|
||||
ContentLength: contentLength,
|
||||
MaxDate: time.Time{},
|
||||
Downloads: 0,
|
||||
MaxDownloads: -1,
|
||||
@@ -438,6 +559,14 @@ func metadataForRequest(contentType string, randomTokenLength int, r *http.Reque
|
||||
metadata.MaxDate = time.Now().Add(time.Hour * 24 * time.Duration(v))
|
||||
}
|
||||
|
||||
if password := r.Header.Get("X-Encrypt-Password"); password != "" {
|
||||
metadata.Encrypted = true
|
||||
metadata.ContentType = "text/plain; charset=utf-8"
|
||||
metadata.DecryptedContentType = contentType
|
||||
} else {
|
||||
metadata.Encrypted = false
|
||||
}
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
@@ -448,56 +577,35 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
contentLength := r.ContentLength
|
||||
|
||||
var reader io.Reader
|
||||
defer safeClose(r.Body)
|
||||
|
||||
reader = r.Body
|
||||
file, err := ioutil.TempFile(s.tempPath, "transfer-")
|
||||
defer s.cleanTmpFile(file)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
defer CloseCheck(r.Body.Close)
|
||||
// queue file to disk, because s3 needs content length
|
||||
// and clamav prescan scans a file
|
||||
n, err := io.Copy(file, r.Body)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
|
||||
if contentLength == -1 {
|
||||
// queue file to disk, because s3 needs content length
|
||||
var err error
|
||||
return
|
||||
}
|
||||
|
||||
f := reader
|
||||
_, err = file.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Cannot reset cache file", http.StatusInternalServerError)
|
||||
|
||||
var b bytes.Buffer
|
||||
|
||||
n, err := io.CopyN(&b, f, _24K+1)
|
||||
if err != nil && err != io.EOF {
|
||||
s.logger.Printf("Error putting new file: %s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
var file *os.File
|
||||
|
||||
if n > _24K {
|
||||
file, err = ioutil.TempFile(s.tempPath, "transfer-")
|
||||
defer s.cleanTmpFile(file)
|
||||
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
n, err = io.Copy(file, io.MultiReader(&b, f))
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
|
||||
reader, err = os.Open(file.Name())
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, err.Error(), 500)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
reader = bytes.NewReader(b.Bytes())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if contentLength < 1 {
|
||||
contentLength = n
|
||||
}
|
||||
|
||||
@@ -509,38 +617,57 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if contentLength == 0 {
|
||||
s.logger.Print("Empty content-length")
|
||||
http.Error(w, "Could not upload empty file", 400)
|
||||
http.Error(w, "Could not upload empty file", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if s.performClamavPrescan {
|
||||
status, err := s.performScan(file.Name())
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not perform prescan", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if status != clamavScanStatusOK {
|
||||
s.logger.Printf("prescan positive: %s", status)
|
||||
http.Error(w, "Clamav prescan found a virus", http.StatusPreconditionFailed)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
contentType := mime.TypeByExtension(filepath.Ext(vars["filename"]))
|
||||
|
||||
token := token(s.randomTokenLength)
|
||||
|
||||
metadata := metadataForRequest(contentType, s.randomTokenLength, r)
|
||||
metadata := metadataForRequest(contentType, contentLength, s.randomTokenLength, r)
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not encode metadata", 500)
|
||||
http.Error(w, "Could not encode metadata", http.StatusInternalServerError)
|
||||
return
|
||||
} else if !metadata.MaxDate.IsZero() && time.Now().After(metadata.MaxDate) {
|
||||
s.logger.Print("Invalid MaxDate")
|
||||
http.Error(w, "Invalid MaxDate, make sure Max-Days is smaller than 290 years", 400)
|
||||
http.Error(w, "Invalid MaxDate, make sure Max-Days is smaller than 290 years", http.StatusBadRequest)
|
||||
return
|
||||
} else if err := s.storage.Put(r.Context(), token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not save metadata", 500)
|
||||
http.Error(w, "Could not save metadata", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
s.logger.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
|
||||
|
||||
var err error
|
||||
reader, err := transformEncryptionReader(file, r.Header.Get("X-Encrypt-Password"))
|
||||
if err != nil {
|
||||
http.Error(w, "Could not crypt file", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err = s.storage.Put(r.Context(), token, filename, reader, contentType, uint64(contentLength)); err != nil {
|
||||
s.logger.Printf("Error putting new file: %s", err.Error())
|
||||
http.Error(w, "Could not save file", 500)
|
||||
http.Error(w, "Could not save file", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -649,6 +776,7 @@ func (metadata metadata) remainingLimitHeaderValues() (remainingDownloads, remai
|
||||
remainingDays = strconv.Itoa(int(timeDifference.Hours()/24) + 1)
|
||||
}
|
||||
|
||||
|
||||
if metadata.MaxDownloads == -1 {
|
||||
remainingDownloads = "n/a"
|
||||
} else {
|
||||
@@ -681,7 +809,7 @@ func (s *Server) checkMetadata(ctx context.Context, token, filename string, incr
|
||||
var metadata metadata
|
||||
|
||||
r, _, err := s.storage.Get(ctx, token, fmt.Sprintf("%s.metadata", filename))
|
||||
defer CloseCheck(r.Close)
|
||||
defer safeClose(r)
|
||||
|
||||
if err != nil {
|
||||
return metadata, err
|
||||
@@ -717,7 +845,7 @@ func (s *Server) checkDeletionToken(ctx context.Context, deletionToken, token, f
|
||||
var metadata metadata
|
||||
|
||||
r, _, err := s.storage.Get(ctx, token, fmt.Sprintf("%s.metadata", filename))
|
||||
defer CloseCheck(r.Close)
|
||||
defer safeClose(r)
|
||||
|
||||
if s.storage.IsNotExist(err) {
|
||||
return errors.New("metadata doesn't exist")
|
||||
@@ -766,7 +894,7 @@ func (s *Server) deleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
} else if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not delete file.", 500)
|
||||
http.Error(w, "Could not delete file.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -796,7 +924,7 @@ func (s *Server) zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
reader, _, err := s.storage.Get(r.Context(), token, filename)
|
||||
defer CloseCheck(reader.Close)
|
||||
defer safeClose(reader)
|
||||
|
||||
if err != nil {
|
||||
if s.storage.IsNotExist(err) {
|
||||
@@ -805,7 +933,7 @@ func (s *Server) zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -820,20 +948,20 @@ func (s *Server) zipHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
http.Error(w, "Internal server error.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(fw, reader); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
http.Error(w, "Internal server error.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := zw.Close(); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
http.Error(w, "Internal server error.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -850,10 +978,10 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Connection", "close")
|
||||
|
||||
gw := gzip.NewWriter(w)
|
||||
defer CloseCheck(gw.Close)
|
||||
defer safeClose(gw)
|
||||
|
||||
zw := tar.NewWriter(gw)
|
||||
defer CloseCheck(zw.Close)
|
||||
defer safeClose(zw)
|
||||
|
||||
for _, key := range strings.Split(files, ",") {
|
||||
key = resolveKey(key, s.proxyPath)
|
||||
@@ -867,7 +995,7 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
reader, contentLength, err := s.storage.Get(r.Context(), token, filename)
|
||||
defer CloseCheck(reader.Close)
|
||||
defer safeClose(reader)
|
||||
|
||||
if err != nil {
|
||||
if s.storage.IsNotExist(err) {
|
||||
@@ -876,7 +1004,7 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -888,13 +1016,13 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err = zw.WriteHeader(header)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
http.Error(w, "Internal server error.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(zw, reader); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
http.Error(w, "Internal server error.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -912,7 +1040,7 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Connection", "close")
|
||||
|
||||
zw := tar.NewWriter(w)
|
||||
defer CloseCheck(zw.Close)
|
||||
defer safeClose(zw)
|
||||
|
||||
for _, key := range strings.Split(files, ",") {
|
||||
key = resolveKey(key, s.proxyPath)
|
||||
@@ -926,7 +1054,7 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
reader, contentLength, err := s.storage.Get(r.Context(), token, filename)
|
||||
defer CloseCheck(reader.Close)
|
||||
defer safeClose(reader)
|
||||
|
||||
if err != nil {
|
||||
if s.storage.IsNotExist(err) {
|
||||
@@ -935,7 +1063,7 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -947,13 +1075,13 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err = zw.WriteHeader(header)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
http.Error(w, "Internal server error.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(zw, reader); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Internal server error.", 500)
|
||||
http.Error(w, "Internal server error.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -980,7 +1108,7 @@ func (s *Server) headHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
} else if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1010,19 +1138,18 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
contentType := metadata.ContentType
|
||||
reader, contentLength, err := s.storage.Get(r.Context(), token, filename)
|
||||
defer CloseCheck(reader.Close)
|
||||
defer safeClose(reader)
|
||||
|
||||
if s.storage.IsNotExist(err) {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Could not retrieve file.", 500)
|
||||
http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var disposition string
|
||||
|
||||
if action == "inline" {
|
||||
disposition = "inline"
|
||||
} else {
|
||||
@@ -1031,9 +1158,7 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
remainingDownloads, remainingDays := metadata.remainingLimitHeaderValues()
|
||||
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("%s; filename=\"%s\"", disposition, filename))
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`%s; filename="%s"`, disposition, filename))
|
||||
w.Header().Set("Connection", "keep-alive")
|
||||
w.Header().Set("X-Remaining-Downloads", remainingDownloads)
|
||||
w.Header().Set("X-Remaining-Days", remainingDays)
|
||||
@@ -1048,14 +1173,14 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Error occurred copying to output stream", 500)
|
||||
http.Error(w, "Error occurred copying to output stream", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = io.Copy(file, reader)
|
||||
if err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Error occurred copying to output stream", 500)
|
||||
http.Error(w, "Error occurred copying to output stream", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1063,9 +1188,24 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(w, reader); err != nil {
|
||||
password := r.Header.Get("X-Decrypt-Password");
|
||||
decryptionReader, err := transformDecryptionReader(reader, password)
|
||||
if err != nil {
|
||||
http.Error(w, "Could not decrypt file", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if metadata.Encrypted && len(password) > 0 {
|
||||
contentType = metadata.DecryptedContentType
|
||||
contentLength = uint64(metadata.ContentLength)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
|
||||
|
||||
if _, err = io.Copy(w, decryptionReader); err != nil {
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, "Error occurred copying to output stream", 500)
|
||||
http.Error(w, "Error occurred copying to output stream", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1136,12 +1276,12 @@ func (s *Server) basicAuthHandler(h http.Handler) http.HandlerFunc {
|
||||
|
||||
username, password, authOK := r.BasicAuth()
|
||||
if !authOK {
|
||||
http.Error(w, "Not authorized", 401)
|
||||
http.Error(w, "Not authorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if username != s.AuthUser || password != s.AuthPass {
|
||||
http.Error(w, "Not authorized", 401)
|
||||
http.Error(w, "Not authorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -76,6 +76,13 @@ func ClamavHost(s string) OptionFn {
|
||||
}
|
||||
}
|
||||
|
||||
// PerformClamavPrescan enables clamav prescan on upload
|
||||
func PerformClamavPrescan(b bool) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.performClamavPrescan = b
|
||||
}
|
||||
}
|
||||
|
||||
// VirustotalKey sets virus total key
|
||||
func VirustotalKey(s string) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
@@ -338,8 +345,9 @@ type Server struct {
|
||||
|
||||
ipFilterOptions *IPFilterOptions
|
||||
|
||||
VirusTotalKey string
|
||||
ClamAVDaemonHost string
|
||||
VirusTotalKey string
|
||||
ClamAVDaemonHost string
|
||||
performClamavPrescan bool
|
||||
|
||||
tempPath string
|
||||
|
||||
@@ -424,13 +432,17 @@ func (s *Server) Run() {
|
||||
s.logger.Panicf("Unable to parse: path=%s, err=%s", path, err)
|
||||
}
|
||||
|
||||
_, err = htmlTemplates.New(stripPrefix(path)).Parse(string(bytes))
|
||||
if err != nil {
|
||||
s.logger.Println("Unable to parse html template", err)
|
||||
if strings.HasSuffix(path, ".html") {
|
||||
_, err = htmlTemplates.New(stripPrefix(path)).Parse(string(bytes))
|
||||
if err != nil {
|
||||
s.logger.Println("Unable to parse html template", err)
|
||||
}
|
||||
}
|
||||
_, err = textTemplates.New(stripPrefix(path)).Parse(string(bytes))
|
||||
if err != nil {
|
||||
s.logger.Println("Unable to parse text template", err)
|
||||
if strings.HasSuffix(path, ".txt") {
|
||||
_, err = textTemplates.New(stripPrefix(path)).Parse(string(bytes))
|
||||
if err != nil {
|
||||
s.logger.Println("Unable to parse text template", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -151,7 +151,7 @@ func (s *LocalStorage) Put(ctx context.Context, token string, filename string, r
|
||||
}
|
||||
|
||||
f, err = os.OpenFile(filepath.Join(path, filename), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
defer CloseCheck(f.Close)
|
||||
defer safeClose(f)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -650,7 +650,7 @@ func getGDriveTokenFromWeb(ctx context.Context, config *oauth2.Config, logger *l
|
||||
// Retrieves a token from a local file.
|
||||
func gDriveTokenFromFile(file string) (*oauth2.Token, error) {
|
||||
f, err := os.Open(file)
|
||||
defer CloseCheck(f.Close)
|
||||
defer safeClose(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -663,7 +663,7 @@ func gDriveTokenFromFile(file string) (*oauth2.Token, error) {
|
||||
func saveGDriveToken(path string, token *oauth2.Token, logger *log.Logger) {
|
||||
logger.Printf("Saving credential file to: %s\n", path)
|
||||
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
defer CloseCheck(f.Close)
|
||||
defer safeClose(f)
|
||||
if err != nil {
|
||||
logger.Fatalf("Unable to cache oauth token: %v", err)
|
||||
}
|
||||
@@ -692,12 +692,16 @@ func NewStorjStorage(access, bucket string, purgeDays int, logger *log.Logger) (
|
||||
|
||||
ctx := fpath.WithTempData(pCtx, "", true)
|
||||
|
||||
uplConf := &uplink.Config{
|
||||
UserAgent: "transfer-sh",
|
||||
}
|
||||
|
||||
parsedAccess, err := uplink.ParseAccess(access)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instance.project, err = uplink.OpenProject(ctx, parsedAccess)
|
||||
instance.project, err = uplConf.OpenProject(ctx, parsedAccess)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/mail"
|
||||
@@ -280,8 +281,12 @@ func formatSize(size int64) string {
|
||||
return fmt.Sprintf("%s %s", strconv.FormatFloat(newVal, 'f', -1, 64), getSuffix)
|
||||
}
|
||||
|
||||
func CloseCheck(f func() error) {
|
||||
if err := f(); err != nil {
|
||||
func safeClose(c io.Closer) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.Close(); err != nil {
|
||||
fmt.Println("Received close error:", err)
|
||||
}
|
||||
}
|
||||
|
@@ -45,14 +45,14 @@ func (s *Server) virusTotalHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
vt, err := virustotal.NewVirusTotal(s.VirusTotalKey)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
reader := r.Body
|
||||
|
||||
result, err := vt.Scan(filename, reader)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
s.logger.Println(result)
|
||||
|
Reference in New Issue
Block a user