@@ -42,7 +42,7 @@ listener | port to use for http (:80) | | | |||
profile-listener | port to use for profiler (:6060)| | | |||
force-https | redirect to https | false | | |||
tls-listener | port to use for https (:443) | | | |||
tls-cert-file | path to tls certificate | | | |||
tls-cert-file | path to tls certificate | | | |||
tls-private-key | path to tls private key | | | |||
temp-path | path to temp folder | system temp | | |||
web-path | path to static web files (for development) | | | |||
@@ -50,9 +50,10 @@ provider | which storage provider to use | (s3 or local) | | |||
aws-access-key | aws access key | | AWS_ACCESS_KEY | |||
aws-secret-key | aws access key | | AWS_SECRET_KEY | |||
bucket | aws bucket | | BUCKET | |||
basedir | path storage for local provider| | | |||
lets-encrypt-hosts | hosts to use for lets encrypt certificates (comma seperated) | | | |||
log | path to log file| | | |||
basedir | path storage for local provider| | | |||
auth-key | key to use for authentication (must be supplied in 'Authorization' header with each request)| | | |||
lets-encrypt-hosts | hosts to use for lets encrypt certificates (comma seperated) | | | |||
log | path to log file| | | |||
If you want to use TLS using lets encrypt certificates, set lets-encrypt-hosts to your domain, set tls-listener to :443 and enable force-https. | |||
@@ -63,7 +64,7 @@ If you want to use TLS using your own certificates, set tls-listener to :443, fo | |||
Make sure your GOPATH is set correctly. | |||
``` | |||
go run main.go -provider=local --listener :8080 --temp-path=/tmp/ --basedir=/tmp/ | |||
go run main.go -provider=local --listener :8080 --temp-path=/tmp/ --basedir=/tmp/ | |||
``` | |||
## Build | |||
@@ -84,7 +85,7 @@ docker run --publish 8080:8080 dutchcoders/transfer.sh:latest --provider local - | |||
Contributions are welcome. | |||
## Creators | |||
## Creators | |||
**Remco Verhoef** | |||
- <https://twitter.com/remco_verhoef> | |||
@@ -94,5 +95,5 @@ Contributions are welcome. | |||
## Copyright and license | |||
Code and documentation copyright 2011-2014 Remco Verhoef. | |||
Code released under [the MIT license](LICENSE). | |||
Code and documentation copyright 2011-2014 Remco Verhoef. | |||
Code released under [the MIT license](LICENSE). |
@@ -139,6 +139,12 @@ var globalFlags = []cli.Flag{ | |||
Name: "profiler", | |||
Usage: "enable profiling", | |||
}, | |||
cli.StringFlag{ | |||
Name: "auth-key", | |||
Usage: "auth-key", | |||
Value: "", | |||
EnvVar: "AUTH_KEY", | |||
}, | |||
} | |||
type Cmd struct { | |||
@@ -198,6 +204,10 @@ func New() *Cmd { | |||
options = append(options, server.VirustotalKey(v)) | |||
} | |||
if v := c.String("auth-key"); v != "" { | |||
options = append(options, server.AuthenticateUploads(v)) | |||
} | |||
if v := c.String("clamav-host"); v != "" { | |||
options = append(options, server.ClamavHost(v)) | |||
} | |||
@@ -729,6 +729,47 @@ func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) { | |||
} | |||
} | |||
func (s *Server) deleteHandler(w http.ResponseWriter, r *http.Request) { | |||
vars := mux.Vars(r) | |||
token := vars["token"] | |||
filename := vars["filename"] | |||
var metadata Metadata | |||
reader, _, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename)) | |||
if s.storage.IsNotExist(err) { | |||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) | |||
return | |||
} else if err != nil { | |||
log.Printf("%s", err.Error()) | |||
http.Error(w, "Could not delete file.", 500) | |||
return | |||
} | |||
defer reader.Close() | |||
if err := json.NewDecoder(reader).Decode(&metadata); err != nil { | |||
log.Printf("%s", err.Error()) | |||
http.Error(w, "Could not delete file.", 500) | |||
return | |||
} | |||
if metadata.Downloads >= metadata.MaxDownloads || time.Now().After(metadata.MaxDate) { | |||
// DELETE FILE AND METADATA | |||
if err := s.storage.Delete(token, filename); err != nil { | |||
log.Printf("%s", err.Error()) | |||
http.Error(w, "Could not delete file.", 500) | |||
return | |||
} | |||
} else { | |||
http.Error(w, "MaxDownloads or MaxDays not exceeded yet.", 500) | |||
return | |||
} | |||
return | |||
} | |||
func (s *Server) RedirectHandler(h http.Handler) http.HandlerFunc { | |||
return func(w http.ResponseWriter, r *http.Request) { | |||
if !s.forceHTTPs { | |||
@@ -760,3 +801,17 @@ func LoveHandler(h http.Handler) http.HandlerFunc { | |||
h.ServeHTTP(w, r) | |||
} | |||
} | |||
func (s *Server) AuthenticatedHandler (h http.Handler) http.HandlerFunc { | |||
return func(w http.ResponseWriter, r *http.Request) { | |||
authKey := r.Header.Get ("Authorization") | |||
if s.AuthKey != "" && authKey != s.AuthKey { | |||
log.Printf("Recieved: Bad Auth Token: %s", authKey) | |||
http.Error(w, errors.New("Bad Auth Token").Error(), 403) | |||
return | |||
} | |||
h.ServeHTTP(w, r) | |||
} | |||
} |
@@ -75,6 +75,12 @@ func VirustotalKey(s string) OptionFn { | |||
} | |||
} | |||
func AuthenticateUploads(key string) OptionFn { | |||
return func(srvr *Server) { | |||
srvr.AuthKey = key | |||
} | |||
} | |||
func Listener(s string) OptionFn { | |||
return func(srvr *Server) { | |||
srvr.ListenerString = s | |||
@@ -189,6 +195,7 @@ type Server struct { | |||
locks map[string]*sync.Mutex | |||
rateLimitRequests int | |||
AuthKey string | |||
storage Storage | |||
@@ -311,16 +318,18 @@ func (s *Server) Run() { | |||
getHandlerFn = ratelimit.Request(ratelimit.IP).Rate(s.rateLimitRequests, 60*time.Second).LimitBy(memory.New())(http.HandlerFunc(getHandlerFn)).ServeHTTP | |||
} | |||
r.HandleFunc("/{token}/{filename}", s.AuthenticatedHandler (http.HandlerFunc (s.deleteHandler))).Methods("DELETE") | |||
r.HandleFunc("/{token}/{filename}", getHandlerFn).Methods("GET") | |||
r.HandleFunc("/get/{token}/{filename}", getHandlerFn).Methods("GET") | |||
r.HandleFunc("/download/{token}/{filename}", getHandlerFn).Methods("GET") | |||
r.HandleFunc("/{filename}/virustotal", s.virusTotalHandler).Methods("PUT") | |||
r.HandleFunc("/{filename}/scan", s.scanHandler).Methods("PUT") | |||
r.HandleFunc("/put/{filename}", s.putHandler).Methods("PUT") | |||
r.HandleFunc("/upload/{filename}", s.putHandler).Methods("PUT") | |||
r.HandleFunc("/{filename}", s.putHandler).Methods("PUT") | |||
r.HandleFunc("/", s.postHandler).Methods("POST") | |||
r.HandleFunc("/put/{filename}", s.AuthenticatedHandler (http.HandlerFunc (s.putHandler))).Methods("PUT") | |||
r.HandleFunc("/upload/{filename}", s.AuthenticatedHandler (http.HandlerFunc (s.putHandler))).Methods("PUT") | |||
r.HandleFunc("/{filename}", s.AuthenticatedHandler (http.HandlerFunc (s.putHandler))).Methods("PUT") | |||
r.HandleFunc("/", s.AuthenticatedHandler (http.HandlerFunc (s.postHandler))).Methods("POST") | |||
// r.HandleFunc("/{page}", viewHandler).Methods("GET") | |||
r.NotFoundHandler = http.HandlerFunc(s.notFoundHandler) | |||
@@ -10,6 +10,7 @@ import ( | |||
"path/filepath" | |||
"strconv" | |||
"sync" | |||
"errors" | |||
"github.com/goamz/goamz/s3" | |||
) | |||
@@ -18,6 +19,7 @@ type Storage interface { | |||
Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error) | |||
Head(token string, filename string) (contentType string, contentLength uint64, err error) | |||
Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) error | |||
Delete(token string, filename string) error | |||
IsNotExist(err error) bool | |||
Type() string | |||
@@ -103,6 +105,27 @@ func (s *LocalStorage) Put(token string, filename string, reader io.Reader, cont | |||
return nil | |||
} | |||
func (s *LocalStorage) Delete(token string, filename string) error { | |||
var err error | |||
userdatafile := filepath.Join(s.basedir, token, filename) | |||
metadatafile := filepath.Join(s.basedir, token, fmt.Sprintf("%s.metadata", filename)) | |||
if err = os.Remove(userdatafile); err != nil { | |||
return err | |||
} | |||
if err = os.Remove(metadatafile); err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
func (s *S3Storage) Delete(token string, filename string) error { | |||
return errors.New("Delete function for S3Storage not yet implemented") | |||
} | |||
type S3Storage struct { | |||
Storage | |||
bucket *s3.Bucket | |||