Multiple fixes

This commit is contained in:
Stefan Benten 2021-07-26 10:59:28 +02:00 committed by GitHub
commit f38eb6fb77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 218 additions and 200 deletions

View file

@ -6,7 +6,6 @@ bin
*.pyc
*.egg-info
.vagrant
.git
.tmp
bower_components
node_modules

View file

@ -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:

View file

@ -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>"

View file

@ -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

View file

@ -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).

View file

@ -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
View file

@ -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
View file

@ -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=

View file

@ -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
}

View file

@ -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)
}

View file

@ -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)
}
}

View file

@ -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
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())
http.Error(w, "Error occurred copying to output stream", 500)
return
}
return
}
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 {
log.Printf("%s", err.Error())
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
}
defer s.cleanTmpFile(file)
_, err = io.Copy(file, reader)
if err != nil {
log.Printf("%s", err.Error())
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
}
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
}
return
}
func (s *Server) RedirectHandler(h http.Handler) http.HandlerFunc {

View file

@ -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
View 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
View 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)
}
}

View file

@ -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)
}