Remove bak files

This commit is contained in:
Remco 2017-03-23 00:03:32 +01:00
parent e947cd3352
commit 964e8c92d7
6 changed files with 0 additions and 1535 deletions

View file

@ -1,65 +0,0 @@
/*
https://github.com/fs111/kurz.go/blob/master/src/codec.go
Originally written and Copyright (c) 2011 André Kelpe
Modifications Copyright (c) 2015 John Ko
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package main
import (
"math"
"strings"
)
const (
// characters used for short-urls
SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
// someone set us up the bomb !!
BASE = int64(len(SYMBOLS))
)
// encodes a number into our *base* representation
// TODO can this be made better with some bitshifting?
func Encode(number int64) string {
rest := number % BASE
// strings are a bit weird in go...
result := string(SYMBOLS[rest])
if number-rest != 0 {
newnumber := (number - rest) / BASE
result = Encode(newnumber) + result
}
return result
}
// Decodes a string given in our encoding and returns the decimal
// integer.
func Decode(input string) int64 {
const floatbase = float64(BASE)
l := len(input)
var sum int = 0
for index := l - 1; index > -1; index -= 1 {
current := string(input[index])
pos := strings.Index(SYMBOLS, current)
sum = sum + (pos * int(math.Pow(floatbase, float64((l-index-1)))))
}
return int64(sum)
}

View file

@ -1,620 +0,0 @@
/*
The MIT License (MIT)
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]
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 main
import (
// _ "transfer.sh/app/handlers"
// _ "transfer.sh/app/utils"
"archive/tar"
"archive/zip"
"bytes"
"compress/gzip"
"errors"
"fmt"
"html"
html_template "html/template"
"io"
"io/ioutil"
"log"
"math/rand"
"mime"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
text_template "text/template"
"time"
clamd "github.com/dutchcoders/go-clamd"
web "github.com/dutchcoders/transfer.sh-web"
"github.com/gorilla/mux"
"github.com/kennygrant/sanitize"
"github.com/russross/blackfriday"
)
var (
html_templates = initHTMLTemplates()
text_templates = initTextTemplates()
)
func stripPrefix(path string) string {
return strings.Replace(path, web.Prefix+"/", "", -1)
}
func initTextTemplates() *text_template.Template {
templateMap := text_template.FuncMap{"format": formatNumber}
// Templates with functions available to them
var templates = text_template.New("").Funcs(templateMap)
return templates
}
func initHTMLTemplates() *html_template.Template {
templateMap := html_template.FuncMap{"format": formatNumber}
// Templates with functions available to them
var templates = html_template.New("").Funcs(templateMap)
return templates
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Approaching Neutral Zone, all systems normal and functioning.")
}
/* The preview handler will show a preview of the content for browsers (accept type text/html), and referer is not transfer.sh */
func previewHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
token := vars["token"]
filename := vars["filename"]
contentType, contentLength, err := storage.Head(token, filename)
if err != nil {
http.Error(w, http.StatusText(404), 404)
return
}
var templatePath string
var content html_template.HTML
switch {
case strings.HasPrefix(contentType, "image/"):
templatePath = "download.image.html"
case strings.HasPrefix(contentType, "video/"):
templatePath = "download.video.html"
case strings.HasPrefix(contentType, "audio/"):
templatePath = "download.audio.html"
case strings.HasPrefix(contentType, "text/"):
templatePath = "download.markdown.html"
var reader io.ReadCloser
if reader, _, _, err = storage.Get(token, filename); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
var data []byte
if data, err = ioutil.ReadAll(reader); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if strings.HasPrefix(contentType, "text/x-markdown") || strings.HasPrefix(contentType, "text/markdown") {
output := blackfriday.MarkdownCommon(data)
content = html_template.HTML(output)
} else if strings.HasPrefix(contentType, "text/plain") {
content = html_template.HTML(fmt.Sprintf("<pre>%s</pre>", html.EscapeString(string(data))))
} else {
templatePath = "download.sandbox.html"
}
default:
templatePath = "download.html"
}
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data := struct {
ContentType string
Content html_template.HTML
Filename string
Url string
ContentLength uint64
}{
contentType,
content,
filename,
r.URL.String(),
contentLength,
}
if err := html_templates.ExecuteTemplate(w, templatePath, data); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
// this handler will output html or text, depending on the
// support of the client (Accept header).
func viewHandler(w http.ResponseWriter, r *http.Request) {
// vars := mux.Vars(r)
if acceptsHtml(r.Header) {
if err := html_templates.ExecuteTemplate(w, "index.html", nil); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
} else {
if err := text_templates.ExecuteTemplate(w, "index.txt", nil); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
}
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(404), 404)
}
func postHandler(w http.ResponseWriter, r *http.Request) {
if err := r.ParseMultipartForm(_24K); nil != err {
log.Printf("%s", err.Error())
http.Error(w, "Error occurred copying to output stream", 500)
return
}
token := Encode(10000000 + int64(rand.Intn(1000000000)))
w.Header().Set("Content-Type", "text/plain")
for _, fheaders := range r.MultipartForm.File {
for _, fheader := range fheaders {
filename := sanitize.Path(filepath.Base(fheader.Filename))
contentType := fheader.Header.Get("Content-Type")
if contentType == "" {
contentType = mime.TypeByExtension(filepath.Ext(fheader.Filename))
}
var f io.Reader
var err error
if f, err = fheader.Open(); err != nil {
log.Printf("%s", err.Error())
http.Error(w, err.Error(), 500)
return
}
var b bytes.Buffer
n, err := io.CopyN(&b, f, _24K+1)
if err != nil && err != io.EOF {
log.Printf("%s", err.Error())
http.Error(w, err.Error(), 500)
return
}
var reader io.Reader
if n > _24K {
file, err := ioutil.TempFile(config.Temp, "transfer-")
if err != nil {
log.Fatal(err)
}
defer file.Close()
n, err = io.Copy(file, io.MultiReader(&b, f))
if err != nil {
os.Remove(file.Name())
log.Printf("%s", err.Error())
http.Error(w, err.Error(), 500)
return
}
reader, err = os.Open(file.Name())
} else {
reader = bytes.NewReader(b.Bytes())
}
contentLength := n
log.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
if err = storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil {
log.Printf("%s", err.Error())
http.Error(w, err.Error(), 500)
return
}
fmt.Fprintf(w, "https://%s/%s/%s\n", ipAddrFromRemoteAddr(r.Host), token, filename)
}
}
}
func scanHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
filename := sanitize.Path(filepath.Base(vars["filename"]))
contentLength := r.ContentLength
contentType := r.Header.Get("Content-Type")
log.Printf("Scanning %s %d %s", filename, contentLength, contentType)
var reader io.Reader
reader = r.Body
c := clamd.NewClamd(config.CLAMAV_DAEMON_HOST)
abort := make(chan bool)
response, err := c.ScanStream(reader, abort)
if err != nil {
log.Printf("%s", err.Error())
http.Error(w, err.Error(), 500)
return
}
select {
case s := <-response:
w.Write([]byte(fmt.Sprintf("%v\n", s.Status)))
case <-time.After(time.Second * 60):
abort <- true
}
close(abort)
}
func putHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
filename := sanitize.Path(filepath.Base(vars["filename"]))
contentLength := r.ContentLength
var reader io.Reader
reader = r.Body
if contentLength == -1 {
// queue file to disk, because s3 needs content length
var err error
var f io.Reader
f = reader
var b bytes.Buffer
n, err := io.CopyN(&b, f, _24K+1)
if err != nil && err != io.EOF {
log.Printf("%s", err.Error())
http.Error(w, err.Error(), 500)
return
}
if n > _24K {
file, err := ioutil.TempFile(config.Temp, "transfer-")
if err != nil {
log.Printf("%s", err.Error())
http.Error(w, err.Error(), 500)
return
}
defer file.Close()
n, err = io.Copy(file, io.MultiReader(&b, f))
if err != nil {
os.Remove(file.Name())
log.Printf("%s", err.Error())
http.Error(w, err.Error(), 500)
return
}
reader, err = os.Open(file.Name())
} else {
reader = bytes.NewReader(b.Bytes())
}
contentLength = n
}
contentType := r.Header.Get("Content-Type")
if contentType == "" {
contentType = mime.TypeByExtension(filepath.Ext(vars["filename"]))
}
token := Encode(10000000 + int64(rand.Intn(1000000000)))
log.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
var err error
if err = storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil {
log.Printf("%s", err.Error())
http.Error(w, errors.New("Could not save file").Error(), 500)
return
}
// w.Statuscode = 200
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintf(w, "https://%s/%s/%s\n", ipAddrFromRemoteAddr(r.Host), token, filename)
}
func zipHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
files := vars["files"]
zipfilename := fmt.Sprintf("transfersh-%d.zip", uint16(time.Now().UnixNano()))
w.Header().Set("Content-Type", "application/zip")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", zipfilename))
w.Header().Set("Connection", "close")
zw := zip.NewWriter(w)
for _, key := range strings.Split(files, ",") {
if strings.HasPrefix(key, "/") {
key = key[1:]
}
key = strings.Replace(key, "\\", "/", -1)
token := strings.Split(key, "/")[0]
filename := sanitize.Path(strings.Split(key, "/")[1])
reader, _, _, err := storage.Get(token, filename)
if err != nil {
if storage.IsNotExist(err) {
http.Error(w, "File not found", 404)
return
} else {
log.Printf("%s", err.Error())
http.Error(w, "Could not retrieve file.", 500)
return
}
}
defer reader.Close()
header := &zip.FileHeader{
Name: strings.Split(key, "/")[1],
Method: zip.Store,
ModifiedTime: uint16(time.Now().UnixNano()),
ModifiedDate: uint16(time.Now().UnixNano()),
}
fw, err := zw.CreateHeader(header)
if err != nil {
log.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())
http.Error(w, "Internal server error.", 500)
return
}
}
if err := zw.Close(); err != nil {
log.Printf("%s", err.Error())
http.Error(w, "Internal server error.", 500)
return
}
}
func tarGzHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
files := vars["files"]
tarfilename := fmt.Sprintf("transfersh-%d.tar.gz", uint16(time.Now().UnixNano()))
w.Header().Set("Content-Type", "application/x-gzip")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", tarfilename))
w.Header().Set("Connection", "close")
os := gzip.NewWriter(w)
defer os.Close()
zw := tar.NewWriter(os)
defer zw.Close()
for _, key := range strings.Split(files, ",") {
if strings.HasPrefix(key, "/") {
key = key[1:]
}
key = strings.Replace(key, "\\", "/", -1)
token := strings.Split(key, "/")[0]
filename := sanitize.Path(strings.Split(key, "/")[1])
reader, _, contentLength, err := storage.Get(token, filename)
if err != nil {
if storage.IsNotExist(err) {
http.Error(w, "File not found", 404)
return
} else {
log.Printf("%s", err.Error())
http.Error(w, "Could not retrieve file.", 500)
return
}
}
defer reader.Close()
header := &tar.Header{
Name: strings.Split(key, "/")[1],
Size: int64(contentLength),
}
err = zw.WriteHeader(header)
if err != nil {
log.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())
http.Error(w, "Internal server error.", 500)
return
}
}
}
func tarHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
files := vars["files"]
tarfilename := fmt.Sprintf("transfersh-%d.tar", uint16(time.Now().UnixNano()))
w.Header().Set("Content-Type", "application/x-tar")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", tarfilename))
w.Header().Set("Connection", "close")
zw := tar.NewWriter(w)
defer zw.Close()
for _, key := range strings.Split(files, ",") {
token := strings.Split(key, "/")[0]
filename := strings.Split(key, "/")[1]
reader, _, contentLength, err := storage.Get(token, filename)
if err != nil {
if storage.IsNotExist(err) {
http.Error(w, "File not found", 404)
return
} else {
log.Printf("%s", err.Error())
http.Error(w, "Could not retrieve file.", 500)
return
}
}
defer reader.Close()
header := &tar.Header{
Name: strings.Split(key, "/")[1],
Size: int64(contentLength),
}
err = zw.WriteHeader(header)
if err != nil {
log.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())
http.Error(w, "Internal server error.", 500)
return
}
}
}
func getHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
token := vars["token"]
filename := vars["filename"]
reader, contentType, contentLength, err := storage.Get(token, filename)
if err != nil {
if storage.IsNotExist(err) {
http.Error(w, "File not found", 404)
return
} else {
log.Printf("%s", err.Error())
http.Error(w, "Could not retrieve file.", 500)
return
}
}
defer reader.Close()
w.Header().Set("Content-Type", contentType)
w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
w.Header().Set("Connection", "close")
if _, err = io.Copy(w, reader); err != nil {
log.Printf("%s", err.Error())
http.Error(w, "Error occurred copying to output stream", 500)
return
}
}
func RedirectHandler(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/health.html" {
} else if ipAddrFromRemoteAddr(r.Host) == "127.0.0.1" {
} else if strings.HasSuffix(ipAddrFromRemoteAddr(r.Host), ".elasticbeanstalk.com") {
} else if ipAddrFromRemoteAddr(r.Host) == "jxm5d6emw5rknovg.onion" {
} else if ipAddrFromRemoteAddr(r.Host) == "transfer.sh" {
if r.Header.Get("X-Forwarded-Proto") != "https" && r.Method == "GET" {
http.Redirect(w, r, "https://transfer.sh"+r.RequestURI, 301)
return
}
} else if ipAddrFromRemoteAddr(r.Host) != "transfer.sh" {
http.Redirect(w, r, "https://transfer.sh"+r.RequestURI, 301)
return
}
h.ServeHTTP(w, r)
}
}
// Create a log handler for every request it receives.
func LoveHandler(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("x-made-with", "<3 by DutchCoders")
w.Header().Set("x-served-by", "Proudly served by DutchCoders")
w.Header().Set("Server", "Transfer.sh HTTP Server 1.0")
h.ServeHTTP(w, r)
}
}

View file

@ -1,239 +0,0 @@
/*
The MIT License (MIT)
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]
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 main
import (
"flag"
"fmt"
"log"
"math/rand"
"mime"
"net/http"
"net/url"
"os"
"os/signal"
"runtime"
"syscall"
"time"
"github.com/PuerkitoBio/ghost/handlers"
"github.com/gorilla/mux"
_ "net/http/pprof"
web "github.com/dutchcoders/transfer.sh-web"
assetfs "github.com/elazarl/go-bindata-assetfs"
)
const SERVER_INFO = "transfer.sh"
// parse request with maximum memory of _24Kilobits
const _24K = (1 << 20) * 24
var storage Storage
type Server struct {
AWS_ACCESS_KEY string
AWS_SECRET_KEY string
BUCKET string
VIRUSTOTAL_KEY string
CLAMAV_DAEMON_HOST string "/tmp/clamd.socket"
Temp string
Path string
}
func New() *Server {
s := &Server{}
s.AWS_ACCESS_KEY = os.Getenv("AWS_ACCESS_KEY_ID")
s.AWS_SECRET_KEY = os.Getenv("AWS_SECRET_KEY")
s.BUCKET = os.Getenv("BUCKET")
s.VIRUSTOTAL_KEY = os.Getenv("VIRUSTOTAL_KEY")
if os.Getenv("CLAMAV_DAEMON_HOST") != "" {
s.CLAMAV_DAEMON_HOST = os.Getenv("CLAMAV_DAEMON_HOST")
}
s.Temp = os.TempDir()
s.Path = "" // "../transfer.sh-web/dist/"
return s
}
func (s *Server) Run() {
rand.Seed(time.Now().UTC().UnixNano())
nCPU := runtime.NumCPU()
runtime.GOMAXPROCS(nCPU)
fmt.Println("Number of CPUs: ", nCPU)
go func() {
fmt.Println("Profiled listening at: :6060")
http.ListenAndServe(":6060", nil)
}()
r := mux.NewRouter()
var fs http.FileSystem
if config.Path != "" {
log.Println("Using static file path: ", config.Path)
fs = http.Dir(config.Path)
html_templates, _ = html_templates.ParseGlob(config.Path + "*.html")
text_templates, _ = text_templates.ParseGlob(config.Path + "*.txt")
} else {
fs = &assetfs.AssetFS{
Asset: web.Asset,
AssetDir: web.AssetDir,
AssetInfo: func(path string) (os.FileInfo, error) {
return os.Stat(path)
},
Prefix: web.Prefix,
}
for _, path := range web.AssetNames() {
bytes, err := web.Asset(path)
if err != nil {
log.Panicf("Unable to parse: path=%s, err=%s", path, err)
}
html_templates.New(stripPrefix(path)).Parse(string(bytes))
text_templates.New(stripPrefix(path)).Parse(string(bytes))
}
}
staticHandler := http.FileServer(fs)
r.PathPrefix("/images/").Handler(staticHandler)
r.PathPrefix("/styles/").Handler(staticHandler)
r.PathPrefix("/scripts/").Handler(staticHandler)
r.PathPrefix("/fonts/").Handler(staticHandler)
r.PathPrefix("/ico/").Handler(staticHandler)
r.PathPrefix("/favicon.ico").Handler(staticHandler)
r.PathPrefix("/robots.txt").Handler(staticHandler)
r.HandleFunc("/({files:.*}).zip", zipHandler).Methods("GET")
r.HandleFunc("/({files:.*}).tar", tarHandler).Methods("GET")
r.HandleFunc("/({files:.*}).tar.gz", tarGzHandler).Methods("GET")
r.HandleFunc("/download/{token}/{filename}", getHandler).Methods("GET")
r.HandleFunc("/{token}/{filename}", previewHandler).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) (match bool) {
match = false
// The file will show a preview page when opening the link in browser directly or
// from external link. If the referer url path and current path are the same it will be
// downloaded.
if !acceptsHtml(r.Header) {
return false
}
match = (r.Referer() == "")
u, err := url.Parse(r.Referer())
if err != nil {
log.Fatal(err)
return
}
match = match || (u.Path != r.URL.Path)
return
}).Methods("GET")
r.HandleFunc("/{token}/{filename}", getHandler).Methods("GET")
r.HandleFunc("/get/{token}/{filename}", getHandler).Methods("GET")
r.HandleFunc("/{filename}/virustotal", virusTotalHandler).Methods("PUT")
r.HandleFunc("/{filename}/scan", scanHandler).Methods("PUT")
r.HandleFunc("/put/{filename}", putHandler).Methods("PUT")
r.HandleFunc("/upload/{filename}", putHandler).Methods("PUT")
r.HandleFunc("/{filename}", putHandler).Methods("PUT")
r.HandleFunc("/health.html", healthHandler).Methods("GET")
r.HandleFunc("/", postHandler).Methods("POST")
// r.HandleFunc("/{page}", viewHandler).Methods("GET")
r.HandleFunc("/", viewHandler).Methods("GET")
r.NotFoundHandler = http.HandlerFunc(notFoundHandler)
port := flag.String("port", "8080", "port number, default: 8080")
temp := flag.String("temp", config.Temp, "")
basedir := flag.String("basedir", "", "")
logpath := flag.String("log", "", "")
provider := flag.String("provider", "s3", "")
flag.Parse()
if *logpath != "" {
f, err := os.OpenFile(*logpath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer f.Close()
log.SetOutput(f)
}
config.Temp = *temp
var err error
switch *provider {
case "s3":
storage, err = NewS3Storage()
case "local":
if *basedir == "" {
log.Panic("basedir not set")
}
storage, err = NewLocalStorage(*basedir)
}
if err != nil {
log.Panic("Error while creating storage.", err)
}
mime.AddExtensionType(".md", "text/x-markdown")
log.Printf("Transfer.sh server started. :\nlistening on port: %v\nusing temp folder: %s\nusing storage provider: %s", *port, config.Temp, *provider)
log.Printf("---------------------------")
s := &http.Server{
Addr: fmt.Sprintf(":%s", *port),
Handler: handlers.PanicHandler(LoveHandler(RedirectHandler(handlers.LogHandler(r, handlers.NewLogOptions(log.Printf, "_default_")))), nil),
}
go func() {
s.ListenAndServe()
}()
term := make(chan os.Signal, 1)
signal.Notify(term, os.Interrupt)
signal.Notify(term, syscall.SIGTERM)
<-term
log.Printf("Server stopped.")
}

View file

@ -1,268 +0,0 @@
package main
import (
"bytes"
"fmt"
"io"
"log"
"mime"
"os"
"path/filepath"
"strconv"
"sync"
"github.com/goamz/goamz/s3"
)
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
IsNotExist(err error) bool
}
type LocalStorage struct {
Storage
basedir string
}
func NewLocalStorage(basedir string) (*LocalStorage, error) {
return &LocalStorage{basedir: basedir}, nil
}
func (s *LocalStorage) Head(token string, filename string) (contentType string, contentLength uint64, err error) {
path := filepath.Join(s.basedir, token, filename)
var fi os.FileInfo
if fi, err = os.Lstat(path); err != nil {
return
}
contentLength = uint64(fi.Size())
contentType = mime.TypeByExtension(filepath.Ext(filename))
return
}
func (s *LocalStorage) Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error) {
path := filepath.Join(s.basedir, token, filename)
// content type , content length
if reader, err = os.Open(path); err != nil {
return
}
var fi os.FileInfo
if fi, err = os.Lstat(path); err != nil {
return
}
contentLength = uint64(fi.Size())
contentType = mime.TypeByExtension(filepath.Ext(filename))
return
}
func (s *LocalStorage) IsNotExist(err error) bool {
return os.IsNotExist(err)
}
func (s *LocalStorage) Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) error {
var f io.WriteCloser
var err error
path := filepath.Join(s.basedir, token)
if err = os.Mkdir(path, 0700); err != nil && !os.IsExist(err) {
return err
}
if f, err = os.OpenFile(filepath.Join(path, filename), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600); err != nil {
fmt.Printf("%s", err)
return err
}
defer f.Close()
if _, err = io.Copy(f, reader); err != nil {
return err
}
return nil
}
type S3Storage struct {
Storage
bucket *s3.Bucket
}
func NewS3Storage() (*S3Storage, error) {
bucket, err := getBucket()
if err != nil {
return nil, err
}
return &S3Storage{bucket: bucket}, nil
}
func (s *S3Storage) Head(token string, filename string) (contentType string, contentLength uint64, err error) {
key := fmt.Sprintf("%s/%s", token, filename)
// content type , content length
response, err := s.bucket.Head(key, map[string][]string{})
if err != nil {
return
}
contentType = response.Header.Get("Content-Type")
contentLength, err = strconv.ParseUint(response.Header.Get("Content-Length"), 10, 0)
if err != nil {
return
}
return
}
func (s *S3Storage) IsNotExist(err error) bool {
log.Printf("IsNotExist: %s, %#v", err.Error(), err)
b := (err.Error() == "The specified key does not exist.")
b = b || (err.Error() == "Access Denied")
return b
}
func (s *S3Storage) Get(token string, filename string) (reader io.ReadCloser, contentType string, contentLength uint64, err error) {
key := fmt.Sprintf("%s/%s", token, filename)
// content type , content length
response, err := s.bucket.GetResponse(key)
if err != nil {
return
}
contentType = response.Header.Get("Content-Type")
contentLength, err = strconv.ParseUint(response.Header.Get("Content-Length"), 10, 0)
if err != nil {
return
}
reader = response.Body
return
}
func (s *S3Storage) Put(token string, filename string, reader io.Reader, contentType string, contentLength uint64) (err error) {
key := fmt.Sprintf("%s/%s", token, filename)
var (
multi *s3.Multi
parts []s3.Part
)
if multi, err = s.bucket.InitMulti(key, contentType, s3.Private); err != nil {
log.Printf(err.Error())
return
}
// 20 mb parts
partsChan := make(chan interface{})
// partsChan := make(chan s3.Part)
go func() {
// maximize to 20 threads
sem := make(chan int, 20)
index := 1
var wg sync.WaitGroup
for {
// buffered in memory because goamz s3 multi needs seekable reader
var (
buffer []byte = make([]byte, (1<<20)*10)
count int
err error
)
// Amazon expects parts of at least 5MB, except for the last one
if count, err = io.ReadAtLeast(reader, buffer, (1<<20)*5); err != nil && err != io.ErrUnexpectedEOF && err != io.EOF {
log.Printf(err.Error())
return
}
// always send minimal 1 part
if err == io.EOF && index > 1 {
log.Printf("Waiting for all parts to finish uploading.")
// wait for all parts to be finished uploading
wg.Wait()
// and close the channel
close(partsChan)
return
}
wg.Add(1)
sem <- 1
// using goroutines because of retries when upload fails
go func(multi *s3.Multi, buffer []byte, index int) {
log.Printf("Uploading part %d %d", index, len(buffer))
defer func() {
log.Printf("Finished part %d %d", index, len(buffer))
wg.Done()
<-sem
}()
partReader := bytes.NewReader(buffer)
var part s3.Part
if part, err = multi.PutPart(index, partReader); err != nil {
log.Printf("Error while uploading part %d %d %s", index, len(buffer), err.Error())
partsChan <- err
return
}
log.Printf("Finished uploading part %d %d", index, len(buffer))
partsChan <- part
}(multi, buffer[:count], index)
index++
}
}()
// wait for all parts to be uploaded
for part := range partsChan {
switch part.(type) {
case s3.Part:
parts = append(parts, part.(s3.Part))
case error:
// abort multi upload
log.Printf("Error during upload, aborting %s.", part.(error).Error())
err = part.(error)
multi.Abort()
return
}
}
log.Printf("Completing upload %d parts", len(parts))
if err = multi.Complete(parts); err != nil {
log.Printf("Error during completing upload %d parts %s", len(parts), err.Error())
return
}
log.Printf("Completed uploading %d", len(parts))
return
}

View file

@ -1,276 +0,0 @@
/*
The MIT License (MIT)
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]
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 main
import (
"math"
"net/http"
"net/mail"
"strconv"
"strings"
"time"
"github.com/goamz/goamz/aws"
"github.com/goamz/goamz/s3"
"github.com/golang/gddo/httputil/header"
)
func getBucket() (*s3.Bucket, error) {
auth, err := aws.GetAuth(config.AWS_ACCESS_KEY, config.AWS_SECRET_KEY, "", time.Time{})
if err != nil {
return nil, err
}
var EUWestWithoutHTTPS = aws.Region{
"eu-west-1",
"https://ec2.eu-west-1.amazonaws.com",
"http://s3-eu-west-1.amazonaws.com",
"",
true,
true,
"https://sdb.eu-west-1.amazonaws.com",
"https://email.eu-west-1.amazonaws.com",
"https://sns.eu-west-1.amazonaws.com",
"https://sqs.eu-west-1.amazonaws.com",
"https://iam.amazonaws.com",
"https://elasticloadbalancing.eu-west-1.amazonaws.com",
"https://dynamodb.eu-west-1.amazonaws.com",
aws.ServiceInfo{"https://monitoring.eu-west-1.amazonaws.com", aws.V2Signature},
"https://autoscaling.eu-west-1.amazonaws.com",
aws.ServiceInfo{"https://rds.eu-west-1.amazonaws.com", aws.V2Signature},
"https://sts.amazonaws.com",
"https://cloudformation.eu-west-1.amazonaws.com",
"https://ecs.eu-west-1.amazonaws.com",
"https://streams.dynamodb.eu-west-1.amazonaws.com",
}
conn := s3.New(auth, EUWestWithoutHTTPS)
b := conn.Bucket(config.BUCKET)
return b, nil
}
func formatNumber(format string, s uint64) string {
return RenderFloat(format, float64(s))
}
var renderFloatPrecisionMultipliers = [10]float64{
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
}
var renderFloatPrecisionRounders = [10]float64{
0.5,
0.05,
0.005,
0.0005,
0.00005,
0.000005,
0.0000005,
0.00000005,
0.000000005,
0.0000000005,
}
func RenderFloat(format string, n float64) string {
// Special cases:
// NaN = "NaN"
// +Inf = "+Infinity"
// -Inf = "-Infinity"
if math.IsNaN(n) {
return "NaN"
}
if n > math.MaxFloat64 {
return "Infinity"
}
if n < -math.MaxFloat64 {
return "-Infinity"
}
// default format
precision := 2
decimalStr := "."
thousandStr := ","
positiveStr := ""
negativeStr := "-"
if len(format) > 0 {
// If there is an explicit format directive,
// then default values are these:
precision = 9
thousandStr = ""
// collect indices of meaningful formatting directives
formatDirectiveChars := []rune(format)
formatDirectiveIndices := make([]int, 0)
for i, char := range formatDirectiveChars {
if char != '#' && char != '0' {
formatDirectiveIndices = append(formatDirectiveIndices, i)
}
}
if len(formatDirectiveIndices) > 0 {
// Directive at index 0:
// Must be a '+'
// Raise an error if not the case
// index: 0123456789
// +0.000,000
// +000,000.0
// +0000.00
// +0000
if formatDirectiveIndices[0] == 0 {
if formatDirectiveChars[formatDirectiveIndices[0]] != '+' {
panic("RenderFloat(): invalid positive sign directive")
}
positiveStr = "+"
formatDirectiveIndices = formatDirectiveIndices[1:]
}
// Two directives:
// First is thousands separator
// Raise an error if not followed by 3-digit
// 0123456789
// 0.000,000
// 000,000.00
if len(formatDirectiveIndices) == 2 {
if (formatDirectiveIndices[1] - formatDirectiveIndices[0]) != 4 {
panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
}
thousandStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
formatDirectiveIndices = formatDirectiveIndices[1:]
}
// One directive:
// Directive is decimal separator
// The number of digit-specifier following the separator indicates wanted precision
// 0123456789
// 0.00
// 000,0000
if len(formatDirectiveIndices) == 1 {
decimalStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
precision = len(formatDirectiveChars) - formatDirectiveIndices[0] - 1
}
}
}
// generate sign part
var signStr string
if n >= 0.000000001 {
signStr = positiveStr
} else if n <= -0.000000001 {
signStr = negativeStr
n = -n
} else {
signStr = ""
n = 0.0
}
// split number into integer and fractional parts
intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])
// generate integer part string
intStr := strconv.Itoa(int(intf))
// add thousand separator if required
if len(thousandStr) > 0 {
for i := len(intStr); i > 3; {
i -= 3
intStr = intStr[:i] + thousandStr + intStr[i:]
}
}
// no fractional part, we can leave now
if precision == 0 {
return signStr + intStr
}
// generate fractional part
fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
// may need padding
if len(fracStr) < precision {
fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
}
return signStr + intStr + decimalStr + fracStr
}
func RenderInteger(format string, n int) string {
return RenderFloat(format, float64(n))
}
// Request.RemoteAddress contains port, which we want to remove i.e.:
// "[::1]:58292" => "[::1]"
func ipAddrFromRemoteAddr(s string) string {
idx := strings.LastIndex(s, ":")
if idx == -1 {
return s
}
return s[:idx]
}
func getIpAddress(r *http.Request) string {
hdr := r.Header
hdrRealIp := hdr.Get("X-Real-Ip")
hdrForwardedFor := hdr.Get("X-Forwarded-For")
if hdrRealIp == "" && hdrForwardedFor == "" {
return ipAddrFromRemoteAddr(r.RemoteAddr)
}
if hdrForwardedFor != "" {
// X-Forwarded-For is potentially a list of addresses separated with ","
parts := strings.Split(hdrForwardedFor, ",")
for i, p := range parts {
parts[i] = strings.TrimSpace(p)
}
// TODO: should return first non-local address
return parts[0]
}
return hdrRealIp
}
func encodeRFC2047(String string) string {
// use mail's rfc2047 to encode any string
addr := mail.Address{String, ""}
return strings.Trim(addr.String(), " <>")
}
func acceptsHtml(hdr http.Header) bool {
actual := header.ParseAccept(hdr, "Accept")
for _, s := range actual {
if s.Value == "text/html" {
return (true)
}
}
return (false)
}

View file

@ -1,67 +0,0 @@
/*
The MIT License (MIT)
Copyright (c) 2014 DutchCoders [https://github.com/dutchcoders/]
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 main
import (
"fmt"
_ "github.com/PuerkitoBio/ghost/handlers"
"github.com/dutchcoders/go-virustotal"
"github.com/gorilla/mux"
"github.com/kennygrant/sanitize"
"io"
"log"
"net/http"
"path/filepath"
)
func virusTotalHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
filename := sanitize.Path(filepath.Base(vars["filename"]))
contentLength := r.ContentLength
contentType := r.Header.Get("Content-Type")
log.Printf("Submitting to VirusTotal: %s %d %s", filename, contentLength, contentType)
apikey := config.VIRUSTOTAL_KEY
vt, err := virustotal.NewVirusTotal(apikey)
if err != nil {
http.Error(w, err.Error(), 500)
}
var reader io.Reader
reader = r.Body
result, err := vt.Scan(filename, reader)
if err != nil {
http.Error(w, err.Error(), 500)
}
log.Println(result)
w.Write([]byte(fmt.Sprintf("%v\n", result.Permalink)))
}