mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2024-11-26 22:20:18 +01:00
Multiple fixes
This commit is contained in:
commit
f38eb6fb77
16 changed files with 218 additions and 200 deletions
|
@ -6,7 +6,6 @@ bin
|
|||
*.pyc
|
||||
*.egg-info
|
||||
.vagrant
|
||||
.git
|
||||
.tmp
|
||||
bower_components
|
||||
node_modules
|
||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
|||
CGO_ENABLED: 0
|
||||
run: |
|
||||
go version
|
||||
go build -tags netgo -ldflags '-a -s -w -extldflags "-static"' -o ./artifacts/transfersh-${GITHUB_REF##*/}-${{ matrix.suffix }}
|
||||
go build -tags netgo -ldflags "-X github.com/dutchcoders/transfer.sh/cmd.Version=${GITHUB_REF##*/} -a -s -w -extldflags '-static'" -o ./artifacts/transfersh-${GITHUB_REF##*/}-${{ matrix.suffix }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
name: Upload artifacts
|
||||
with:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Default to Go 1.15
|
||||
ARG GO_VERSION=1.15
|
||||
# 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 go build -tags netgo -ldflags '-a -s -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
|
||||
|
|
|
@ -224,4 +224,7 @@ Contributions are welcome.
|
|||
## 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).
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
var Version = "1.2.4"
|
||||
var Version = "0.0.0"
|
||||
var helpTemplate = `NAME:
|
||||
{{.Name}} - {{.Usage}}
|
||||
|
||||
|
@ -274,7 +274,7 @@ var globalFlags = []cli.Flag{
|
|||
Value: "",
|
||||
EnvVar: "CORS_DOMAINS",
|
||||
},
|
||||
cli.Int64Flag{
|
||||
cli.IntFlag{
|
||||
Name: "random-token-length",
|
||||
Usage: "",
|
||||
Value: 6,
|
||||
|
@ -383,7 +383,7 @@ func New() *Cmd {
|
|||
options = append(options, server.RateLimit(v))
|
||||
}
|
||||
|
||||
v := c.Int64("random-token-length")
|
||||
v := c.Int("random-token-length")
|
||||
options = append(options, server.RandomTokenLength(v))
|
||||
|
||||
purgeDays := c.Int("purge-days")
|
||||
|
|
2
go.mod
2
go.mod
|
@ -11,7 +11,7 @@ require (
|
|||
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-20210212072623-ac7014a9c3a7
|
||||
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
|
||||
|
|
9
go.sum
9
go.sum
|
@ -92,6 +92,14 @@ github.com/dutchcoders/go-virustotal v0.0.0-20140923143438-24cc8e6fa329 h1:ERqCk
|
|||
github.com/dutchcoders/go-virustotal v0.0.0-20140923143438-24cc8e6fa329/go.mod h1:G5qOfE5bQZ5scycLpB7fYWgN4y3xdfXo+pYWM8z2epY=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210212072623-ac7014a9c3a7 h1:zKJw+RxTDbypWVb0HfPs43bj/ee65Bl7rIDPO7HixrQ=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210212072623-ac7014a9c3a7/go.mod h1:jTzXZabwihvQgvmySgD4f4GNszimkXK3o8x1ucH1z5Q=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210717081259-8b8af59a0fae h1:JalbO1PKAsbSYQBW6Q4aXbgj2w4bWofdrHxRRwqRgDc=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210717081259-8b8af59a0fae/go.mod h1:F6Q37CxDh2MHr5KXkcZmNB3tdkK7v+bgE+OpBY+9ilI=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210723091746-c17d678a22f3 h1:CM9FGBPXLXhvKo0TuO4CKKdZLah6esP1SAfPzZDjEB0=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210723091746-c17d678a22f3/go.mod h1:F6Q37CxDh2MHr5KXkcZmNB3tdkK7v+bgE+OpBY+9ilI=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210723093538-596fe60a5dd5 h1:M6GI6DvsFgBGpp3+V+VB5okP1BGXISltz7acVYWWFOQ=
|
||||
github.com/dutchcoders/transfer.sh-web v0.0.0-20210723093538-596fe60a5dd5/go.mod h1:F6Q37CxDh2MHr5KXkcZmNB3tdkK7v+bgE+OpBY+9ilI=
|
||||
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=
|
||||
|
@ -249,6 +257,7 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
|
|||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shuLhan/go-bindata v4.0.0+incompatible/go.mod h1:pkcPAATLBDD2+SpAPnX5vEM90F7fcwHCvvLCMXcmw3g=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
|
|
|
@ -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,78 +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"
|
||||
"math/rand"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// characters used for short-urls
|
||||
SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
// someone set us up the bomb !!
|
||||
BASE = float64(len(SYMBOLS))
|
||||
|
||||
// init seed encode number
|
||||
INIT_SEED = float64(-1)
|
||||
)
|
||||
|
||||
// encodes a number into our *base* representation
|
||||
// TODO can this be made better with some bitshifting?
|
||||
func Encode(number float64, length int64) string {
|
||||
if number == INIT_SEED {
|
||||
seed := math.Pow(float64(BASE), float64(length))
|
||||
number = seed + (rand.Float64() * seed) // start with seed to enforce desired length
|
||||
}
|
||||
|
||||
rest := int64(math.Mod(number, BASE))
|
||||
// strings are a bit weird in go...
|
||||
result := string(SYMBOLS[rest])
|
||||
if rest > 0 && number-float64(rest) != 0 {
|
||||
newnumber := (number - float64(rest)) / BASE
|
||||
result = Encode(newnumber, length) + result
|
||||
} else {
|
||||
// it would always be 1 because of starting with seed and we want to skip
|
||||
return ""
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package server
|
||||
|
||||
import "testing"
|
||||
|
||||
func BenchmarkEncodeConcat(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = Encode(INIT_SEED, 5) + Encode(INIT_SEED, 5)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeLonger(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = Encode(INIT_SEED, 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
|
||||
|
@ -40,7 +42,6 @@ import (
|
|||
html_template "html/template"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -125,7 +126,7 @@ func (s *Server) previewHandler(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
|
||||
}
|
||||
|
@ -237,16 +238,34 @@ func (s *Server) viewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
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) {
|
||||
|
@ -272,12 +291,12 @@ 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(INIT_SEED, s.randomTokenLength)
|
||||
token := Token(s.randomTokenLength)
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
|
||||
|
@ -290,7 +309,7 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
|||
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
|
||||
}
|
||||
|
@ -299,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
|
||||
}
|
||||
|
@ -310,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
|
||||
}
|
||||
|
@ -330,7 +349,7 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
|||
contentLength := n
|
||||
|
||||
if s.maxUploadSize > 0 && contentLength > s.maxUploadSize {
|
||||
log.Print("Entity too large")
|
||||
s.logger.Print("Entity too large")
|
||||
http.Error(w, http.StatusText(http.StatusRequestEntityTooLarge), http.StatusRequestEntityTooLarge)
|
||||
return
|
||||
}
|
||||
|
@ -339,23 +358,23 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
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)
|
||||
|
||||
cleanTmpFile(file)
|
||||
s.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())
|
||||
s.logger.Printf("%s", err.Error())
|
||||
http.Error(w, errors.New("Could not save metadata").Error(), 500)
|
||||
|
||||
cleanTmpFile(file)
|
||||
s.cleanTmpFile(file)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
|
||||
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
|
||||
|
||||
|
@ -365,21 +384,21 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
|
|||
relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -399,13 +418,13 @@ type Metadata struct {
|
|||
DeletionToken string
|
||||
}
|
||||
|
||||
func MetadataForRequest(contentType string, randomTokenLength int64, r *http.Request) Metadata {
|
||||
func MetadataForRequest(contentType string, randomTokenLength int, r *http.Request) Metadata {
|
||||
metadata := Metadata{
|
||||
ContentType: strings.ToLower(contentType),
|
||||
MaxDate: time.Time{},
|
||||
Downloads: 0,
|
||||
MaxDownloads: -1,
|
||||
DeletionToken: Encode(INIT_SEED, randomTokenLength) + Encode(INIT_SEED, randomTokenLength),
|
||||
DeletionToken: Token(randomTokenLength) + Token(randomTokenLength),
|
||||
}
|
||||
|
||||
if v := r.Header.Get("Max-Downloads"); v == "" {
|
||||
|
@ -447,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
|
||||
}
|
||||
|
@ -457,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
|
||||
}
|
||||
|
@ -480,40 +499,40 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if s.maxUploadSize > 0 && contentLength > s.maxUploadSize {
|
||||
log.Print("Entity too large")
|
||||
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 := mime.TypeByExtension(filepath.Ext(vars["filename"]))
|
||||
|
||||
token := Encode(INIT_SEED, s.randomTokenLength)
|
||||
token := Token(s.randomTokenLength)
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -637,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) {
|
||||
|
@ -723,7 +741,7 @@ func (s *Server) purgeHandler() {
|
|||
select {
|
||||
case <-ticker.C:
|
||||
err := s.storage.Purge(s.purgeDays)
|
||||
log.Printf("error cleaning up expired files: %v", err)
|
||||
s.logger.Printf("error cleaning up expired files: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
@ -737,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
|
||||
}
|
||||
|
@ -747,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
|
||||
}
|
||||
|
@ -773,7 +791,7 @@ 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
|
||||
}
|
||||
|
||||
|
@ -784,7 +802,7 @@ func (s *Server) zipHandler(w http.ResponseWriter, r *http.Request) {
|
|||
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
|
||||
}
|
||||
|
@ -802,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
|
||||
}
|
||||
|
@ -845,7 +863,7 @@ 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
|
||||
}
|
||||
|
||||
|
@ -855,7 +873,7 @@ func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
|
|||
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 +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
|
||||
}
|
||||
|
@ -904,7 +922,7 @@ 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
|
||||
}
|
||||
|
||||
|
@ -914,7 +932,7 @@ func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
|
|||
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
|
||||
}
|
||||
|
@ -929,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
|
||||
}
|
||||
|
@ -951,7 +969,7 @@ 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
|
||||
}
|
||||
|
@ -962,7 +980,7 @@ func (s *Server) headHandler(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 retrieve file.", 500)
|
||||
return
|
||||
}
|
||||
|
@ -986,7 +1004,7 @@ 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
|
||||
}
|
||||
|
@ -997,7 +1015,7 @@ func (s *Server) getHandler(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 retrieve file.", 500)
|
||||
return
|
||||
}
|
||||
|
@ -1025,41 +1043,34 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
|
|||
reader = ioutil.NopCloser(bluemonday.UGCPolicy().SanitizeReader(reader))
|
||||
}
|
||||
|
||||
if w.Header().Get("Range") == "" {
|
||||
if _, err = io.Copy(w, reader); err != nil {
|
||||
log.Printf("%s", err.Error())
|
||||
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 {
|
||||
|
|
|
@ -161,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)
|
||||
|
@ -187,7 +187,7 @@ func RateLimit(requests int) OptionFn {
|
|||
}
|
||||
}
|
||||
|
||||
func RandomTokenLength(length int64) OptionFn {
|
||||
func RandomTokenLength(length int) OptionFn {
|
||||
return func(srvr *Server) {
|
||||
srvr.randomTokenLength = length
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ type Server struct {
|
|||
|
||||
profilerEnabled bool
|
||||
|
||||
locks map[string]*sync.Mutex
|
||||
locks sync.Map
|
||||
|
||||
maxUploadSize int64
|
||||
rateLimitRequests int
|
||||
|
@ -300,7 +300,7 @@ type Server struct {
|
|||
|
||||
forceHTTPs bool
|
||||
|
||||
randomTokenLength int64
|
||||
randomTokenLength int
|
||||
|
||||
ipFilterOptions *IPFilterOptions
|
||||
|
||||
|
@ -329,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 {
|
||||
|
|
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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue