mirror of
https://github.com/dutchcoders/transfer.sh.git
synced 2024-12-27 21:00:19 +01:00
Remove bak files
This commit is contained in:
parent
e947cd3352
commit
964e8c92d7
6 changed files with 0 additions and 1535 deletions
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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.")
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)))
|
||||
}
|
Loading…
Reference in a new issue