|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- /*
- 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.")
- }
|