server.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. /*
  2. The MIT License (MIT)
  3. Copyright (c) 2014-2017 DutchCoders [https://github.com/dutchcoders/]
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in
  11. all copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  18. THE SOFTWARE.
  19. */
  20. package server
  21. import (
  22. "context"
  23. cryptoRand "crypto/rand"
  24. "crypto/tls"
  25. "encoding/binary"
  26. "errors"
  27. "log"
  28. "math/rand"
  29. "mime"
  30. "net/http"
  31. _ "net/http/pprof"
  32. "net/url"
  33. "os"
  34. "os/signal"
  35. "path/filepath"
  36. "strings"
  37. "sync"
  38. "syscall"
  39. "time"
  40. "github.com/PuerkitoBio/ghost/handlers"
  41. "github.com/VojtechVitek/ratelimit"
  42. "github.com/VojtechVitek/ratelimit/memory"
  43. gorillaHandlers "github.com/gorilla/handlers"
  44. "github.com/gorilla/mux"
  45. "github.com/tg123/go-htpasswd"
  46. "golang.org/x/crypto/acme/autocert"
  47. web "github.com/dutchcoders/transfer.sh-web"
  48. "github.com/dutchcoders/transfer.sh/server/storage"
  49. assetfs "github.com/elazarl/go-bindata-assetfs"
  50. )
  51. // parse request with maximum memory of _24Kilobits
  52. const _24K = (1 << 3) * 24
  53. // parse request with maximum memory of _5Megabytes
  54. const _5M = (1 << 20) * 5
  55. // OptionFn is the option function type
  56. type OptionFn func(*Server)
  57. // ClamavHost sets clamav host
  58. func ClamavHost(s string) OptionFn {
  59. return func(srvr *Server) {
  60. srvr.ClamAVDaemonHost = s
  61. }
  62. }
  63. // PerformClamavPrescan enables clamav prescan on upload
  64. func PerformClamavPrescan(b bool) OptionFn {
  65. return func(srvr *Server) {
  66. srvr.performClamavPrescan = b
  67. }
  68. }
  69. // VirustotalKey sets virus total key
  70. func VirustotalKey(s string) OptionFn {
  71. return func(srvr *Server) {
  72. srvr.VirusTotalKey = s
  73. }
  74. }
  75. // Listener set listener
  76. func Listener(s string) OptionFn {
  77. return func(srvr *Server) {
  78. srvr.ListenerString = s
  79. }
  80. }
  81. // CorsDomains sets CORS domains
  82. func CorsDomains(s string) OptionFn {
  83. return func(srvr *Server) {
  84. srvr.CorsDomains = s
  85. }
  86. }
  87. // EmailContact sets email contact
  88. func EmailContact(emailContact string) OptionFn {
  89. return func(srvr *Server) {
  90. srvr.emailContact = emailContact
  91. }
  92. }
  93. // GoogleAnalytics sets GA key
  94. func GoogleAnalytics(gaKey string) OptionFn {
  95. return func(srvr *Server) {
  96. srvr.gaKey = gaKey
  97. }
  98. }
  99. // UserVoice sets UV key
  100. func UserVoice(userVoiceKey string) OptionFn {
  101. return func(srvr *Server) {
  102. srvr.userVoiceKey = userVoiceKey
  103. }
  104. }
  105. // TLSListener sets TLS listener and option
  106. func TLSListener(s string, t bool) OptionFn {
  107. return func(srvr *Server) {
  108. srvr.TLSListenerString = s
  109. srvr.TLSListenerOnly = t
  110. }
  111. }
  112. // ProfileListener sets profile listener
  113. func ProfileListener(s string) OptionFn {
  114. return func(srvr *Server) {
  115. srvr.ProfileListenerString = s
  116. }
  117. }
  118. // WebPath sets web path
  119. func WebPath(s string) OptionFn {
  120. return func(srvr *Server) {
  121. if s[len(s)-1:] != "/" {
  122. s = filepath.Join(s, "")
  123. }
  124. srvr.webPath = s
  125. }
  126. }
  127. // ProxyPath sets proxy path
  128. func ProxyPath(s string) OptionFn {
  129. return func(srvr *Server) {
  130. if s[len(s)-1:] != "/" {
  131. s = filepath.Join(s, "")
  132. }
  133. srvr.proxyPath = s
  134. }
  135. }
  136. // ProxyPort sets proxy port
  137. func ProxyPort(s string) OptionFn {
  138. return func(srvr *Server) {
  139. srvr.proxyPort = s
  140. }
  141. }
  142. // TempPath sets temp path
  143. func TempPath(s string) OptionFn {
  144. return func(srvr *Server) {
  145. if s[len(s)-1:] != "/" {
  146. s = filepath.Join(s, "")
  147. }
  148. srvr.tempPath = s
  149. }
  150. }
  151. // LogFile sets log file
  152. func LogFile(logger *log.Logger, s string) OptionFn {
  153. return func(srvr *Server) {
  154. f, err := os.OpenFile(s, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
  155. if err != nil {
  156. logger.Fatalf("error opening file: %v", err)
  157. }
  158. logger.SetOutput(f)
  159. srvr.logger = logger
  160. }
  161. }
  162. // Logger sets logger
  163. func Logger(logger *log.Logger) OptionFn {
  164. return func(srvr *Server) {
  165. srvr.logger = logger
  166. }
  167. }
  168. // MaxUploadSize sets max upload size
  169. func MaxUploadSize(kbytes int64) OptionFn {
  170. return func(srvr *Server) {
  171. srvr.maxUploadSize = kbytes * 1024
  172. }
  173. }
  174. // RateLimit set rate limit
  175. func RateLimit(requests int) OptionFn {
  176. return func(srvr *Server) {
  177. srvr.rateLimitRequests = requests
  178. }
  179. }
  180. // RandomTokenLength sets random token length
  181. func RandomTokenLength(length int) OptionFn {
  182. return func(srvr *Server) {
  183. srvr.randomTokenLength = length
  184. }
  185. }
  186. // Purge sets purge days and option
  187. func Purge(days, interval int) OptionFn {
  188. return func(srvr *Server) {
  189. srvr.purgeDays = time.Duration(days) * time.Hour * 24
  190. srvr.purgeInterval = time.Duration(interval) * time.Hour
  191. }
  192. }
  193. // ForceHTTPS sets forcing https
  194. func ForceHTTPS() OptionFn {
  195. return func(srvr *Server) {
  196. srvr.forceHTTPS = true
  197. }
  198. }
  199. // EnableProfiler sets enable profiler
  200. func EnableProfiler() OptionFn {
  201. return func(srvr *Server) {
  202. srvr.profilerEnabled = true
  203. }
  204. }
  205. // UseStorage set storage to use
  206. func UseStorage(s storage.Storage) OptionFn {
  207. return func(srvr *Server) {
  208. srvr.storage = s
  209. }
  210. }
  211. // UseLetsEncrypt set letsencrypt usage
  212. func UseLetsEncrypt(hosts []string) OptionFn {
  213. return func(srvr *Server) {
  214. cacheDir := "./cache/"
  215. m := autocert.Manager{
  216. Prompt: autocert.AcceptTOS,
  217. Cache: autocert.DirCache(cacheDir),
  218. HostPolicy: func(_ context.Context, host string) error {
  219. found := false
  220. for _, h := range hosts {
  221. found = found || strings.HasSuffix(host, h)
  222. }
  223. if !found {
  224. return errors.New("acme/autocert: host not configured")
  225. }
  226. return nil
  227. },
  228. }
  229. srvr.tlsConfig = m.TLSConfig()
  230. srvr.tlsConfig.GetCertificate = m.GetCertificate
  231. }
  232. }
  233. // TLSConfig sets TLS config
  234. func TLSConfig(cert, pk string) OptionFn {
  235. certificate, err := tls.LoadX509KeyPair(cert, pk)
  236. return func(srvr *Server) {
  237. srvr.tlsConfig = &tls.Config{
  238. GetCertificate: func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
  239. return &certificate, err
  240. },
  241. }
  242. }
  243. }
  244. // HTTPAuthCredentials sets basic http auth credentials
  245. func HTTPAuthCredentials(user string, pass string) OptionFn {
  246. return func(srvr *Server) {
  247. srvr.authUser = user
  248. srvr.authPass = pass
  249. }
  250. }
  251. // HTTPAuthHtpasswd sets basic http auth htpasswd file
  252. func HTTPAuthHtpasswd(htpasswdPath string) OptionFn {
  253. return func(srvr *Server) {
  254. srvr.authHtpasswd = htpasswdPath
  255. }
  256. }
  257. // HTTPAUTHFilterOptions sets basic http auth ips whitelist
  258. func HTTPAUTHFilterOptions(options IPFilterOptions) OptionFn {
  259. for i, allowedIP := range options.AllowedIPs {
  260. options.AllowedIPs[i] = strings.TrimSpace(allowedIP)
  261. }
  262. return func(srvr *Server) {
  263. srvr.authIPFilterOptions = &options
  264. }
  265. }
  266. // FilterOptions sets ip filtering
  267. func FilterOptions(options IPFilterOptions) OptionFn {
  268. for i, allowedIP := range options.AllowedIPs {
  269. options.AllowedIPs[i] = strings.TrimSpace(allowedIP)
  270. }
  271. for i, blockedIP := range options.BlockedIPs {
  272. options.BlockedIPs[i] = strings.TrimSpace(blockedIP)
  273. }
  274. return func(srvr *Server) {
  275. srvr.ipFilterOptions = &options
  276. }
  277. }
  278. // Server is the main application
  279. type Server struct {
  280. authUser string
  281. authPass string
  282. authHtpasswd string
  283. authIPFilterOptions *IPFilterOptions
  284. htpasswdFile *htpasswd.File
  285. authIPFilter *ipFilter
  286. logger *log.Logger
  287. tlsConfig *tls.Config
  288. profilerEnabled bool
  289. locks sync.Map
  290. maxUploadSize int64
  291. rateLimitRequests int
  292. purgeDays time.Duration
  293. purgeInterval time.Duration
  294. storage storage.Storage
  295. forceHTTPS bool
  296. randomTokenLength int
  297. ipFilterOptions *IPFilterOptions
  298. VirusTotalKey string
  299. ClamAVDaemonHost string
  300. performClamavPrescan bool
  301. tempPath string
  302. webPath string
  303. proxyPath string
  304. proxyPort string
  305. emailContact string
  306. gaKey string
  307. userVoiceKey string
  308. TLSListenerOnly bool
  309. CorsDomains string
  310. ListenerString string
  311. TLSListenerString string
  312. ProfileListenerString string
  313. Certificate string
  314. LetsEncryptCache string
  315. }
  316. // New is the factory fot Server
  317. func New(options ...OptionFn) (*Server, error) {
  318. s := &Server{
  319. locks: sync.Map{},
  320. }
  321. for _, optionFn := range options {
  322. optionFn(s)
  323. }
  324. return s, nil
  325. }
  326. var theRand *rand.Rand
  327. func init() {
  328. var seedBytes [8]byte
  329. if _, err := cryptoRand.Read(seedBytes[:]); err != nil {
  330. panic("cannot obtain cryptographically secure seed")
  331. }
  332. theRand = rand.New(rand.NewSource(int64(binary.LittleEndian.Uint64(seedBytes[:]))))
  333. }
  334. // Run starts Server
  335. func (s *Server) Run() {
  336. listening := false
  337. if s.profilerEnabled {
  338. listening = true
  339. go func() {
  340. s.logger.Println("Profiled listening at: :6060")
  341. _ = http.ListenAndServe(":6060", nil)
  342. }()
  343. }
  344. r := mux.NewRouter()
  345. var fs http.FileSystem
  346. if s.webPath != "" {
  347. s.logger.Println("Using static file path: ", s.webPath)
  348. fs = http.Dir(s.webPath)
  349. htmlTemplates, _ = htmlTemplates.ParseGlob(filepath.Join(s.webPath, "*.html"))
  350. textTemplates, _ = textTemplates.ParseGlob(filepath.Join(s.webPath, "*.txt"))
  351. } else {
  352. fs = &assetfs.AssetFS{
  353. Asset: web.Asset,
  354. AssetDir: web.AssetDir,
  355. AssetInfo: func(path string) (os.FileInfo, error) {
  356. return os.Stat(path)
  357. },
  358. Prefix: web.Prefix,
  359. }
  360. for _, path := range web.AssetNames() {
  361. bytes, err := web.Asset(path)
  362. if err != nil {
  363. s.logger.Panicf("Unable to parse: path=%s, err=%s", path, err)
  364. }
  365. if strings.HasSuffix(path, ".html") {
  366. _, err = htmlTemplates.New(stripPrefix(path)).Parse(string(bytes))
  367. if err != nil {
  368. s.logger.Println("Unable to parse html template", err)
  369. }
  370. }
  371. if strings.HasSuffix(path, ".txt") {
  372. _, err = textTemplates.New(stripPrefix(path)).Parse(string(bytes))
  373. if err != nil {
  374. s.logger.Println("Unable to parse text template", err)
  375. }
  376. }
  377. }
  378. }
  379. staticHandler := http.FileServer(fs)
  380. r.PathPrefix("/images/").Handler(staticHandler).Methods("GET")
  381. r.PathPrefix("/styles/").Handler(staticHandler).Methods("GET")
  382. r.PathPrefix("/scripts/").Handler(staticHandler).Methods("GET")
  383. r.PathPrefix("/fonts/").Handler(staticHandler).Methods("GET")
  384. r.PathPrefix("/ico/").Handler(staticHandler).Methods("GET")
  385. r.HandleFunc("/favicon.ico", staticHandler.ServeHTTP).Methods("GET")
  386. r.HandleFunc("/robots.txt", staticHandler.ServeHTTP).Methods("GET")
  387. r.HandleFunc("/{filename:(?:favicon\\.ico|robots\\.txt|health\\.html)}", s.basicAuthHandler(http.HandlerFunc(s.putHandler))).Methods("PUT")
  388. r.HandleFunc("/health.html", healthHandler).Methods("GET")
  389. r.HandleFunc("/", s.viewHandler).Methods("GET")
  390. r.HandleFunc("/({files:.*}).zip", s.zipHandler).Methods("GET")
  391. r.HandleFunc("/({files:.*}).tar", s.tarHandler).Methods("GET")
  392. r.HandleFunc("/({files:.*}).tar.gz", s.tarGzHandler).Methods("GET")
  393. r.HandleFunc("/{token}/{filename}", s.headHandler).Methods("HEAD")
  394. r.HandleFunc("/{action:(?:download|get|inline)}/{token}/{filename}", s.headHandler).Methods("HEAD")
  395. r.HandleFunc("/{token}/{filename}", s.previewHandler).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) (match bool) {
  396. // The file will show a preview page when opening the link in browser directly or
  397. // from external link. If the referer url path and current path are the same it will be
  398. // downloaded.
  399. if !acceptsHTML(r.Header) {
  400. return false
  401. }
  402. match = r.Referer() == ""
  403. u, err := url.Parse(r.Referer())
  404. if err != nil {
  405. s.logger.Fatal(err)
  406. return
  407. }
  408. match = match || (u.Path != r.URL.Path)
  409. return
  410. }).Methods("GET")
  411. getHandlerFn := s.getHandler
  412. if s.rateLimitRequests > 0 {
  413. getHandlerFn = ratelimit.Request(ratelimit.IP).Rate(s.rateLimitRequests, 60*time.Second).LimitBy(memory.New())(http.HandlerFunc(getHandlerFn)).ServeHTTP
  414. }
  415. r.HandleFunc("/{token}/{filename}", getHandlerFn).Methods("GET")
  416. r.HandleFunc("/{action:(?:download|get|inline)}/{token}/{filename}", getHandlerFn).Methods("GET")
  417. r.HandleFunc("/{filename}/virustotal", s.virusTotalHandler).Methods("PUT")
  418. r.HandleFunc("/{filename}/scan", s.scanHandler).Methods("PUT")
  419. r.HandleFunc("/put/{filename}", s.basicAuthHandler(http.HandlerFunc(s.putHandler))).Methods("PUT")
  420. r.HandleFunc("/upload/{filename}", s.basicAuthHandler(http.HandlerFunc(s.putHandler))).Methods("PUT")
  421. r.HandleFunc("/{filename}", s.basicAuthHandler(http.HandlerFunc(s.putHandler))).Methods("PUT")
  422. r.HandleFunc("/", s.basicAuthHandler(http.HandlerFunc(s.postHandler))).Methods("POST")
  423. // r.HandleFunc("/{page}", viewHandler).Methods("GET")
  424. r.HandleFunc("/{token}/{filename}/{deletionToken}", s.deleteHandler).Methods("DELETE")
  425. r.NotFoundHandler = http.HandlerFunc(s.notFoundHandler)
  426. _ = mime.AddExtensionType(".md", "text/x-markdown")
  427. s.logger.Printf("Transfer.sh server started.\nusing temp folder: %s\nusing storage provider: %s", s.tempPath, s.storage.Type())
  428. var cors func(http.Handler) http.Handler
  429. if len(s.CorsDomains) > 0 {
  430. cors = gorillaHandlers.CORS(
  431. gorillaHandlers.AllowedHeaders([]string{"*"}),
  432. gorillaHandlers.AllowedOrigins(strings.Split(s.CorsDomains, ",")),
  433. gorillaHandlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"}),
  434. )
  435. } else {
  436. cors = func(h http.Handler) http.Handler {
  437. return h
  438. }
  439. }
  440. h := handlers.PanicHandler(
  441. ipFilterHandler(
  442. handlers.LogHandler(
  443. LoveHandler(
  444. s.RedirectHandler(cors(r))),
  445. handlers.NewLogOptions(s.logger.Printf, "_default_"),
  446. ),
  447. s.ipFilterOptions,
  448. ),
  449. nil,
  450. )
  451. if !s.TLSListenerOnly {
  452. listening = true
  453. s.logger.Printf("starting to listen on: %v\n", s.ListenerString)
  454. go func() {
  455. srvr := &http.Server{
  456. Addr: s.ListenerString,
  457. Handler: h,
  458. }
  459. if err := srvr.ListenAndServe(); err != nil {
  460. s.logger.Fatal(err)
  461. }
  462. }()
  463. }
  464. if s.TLSListenerString != "" {
  465. listening = true
  466. s.logger.Printf("starting to listen for TLS on: %v\n", s.TLSListenerString)
  467. go func() {
  468. srvr := &http.Server{
  469. Addr: s.TLSListenerString,
  470. Handler: h,
  471. TLSConfig: s.tlsConfig,
  472. }
  473. if err := srvr.ListenAndServeTLS("", ""); err != nil {
  474. s.logger.Fatal(err)
  475. }
  476. }()
  477. }
  478. s.logger.Printf("---------------------------")
  479. if s.purgeDays > 0 {
  480. go s.purgeHandler()
  481. }
  482. term := make(chan os.Signal, 1)
  483. signal.Notify(term, os.Interrupt)
  484. signal.Notify(term, syscall.SIGTERM)
  485. if listening {
  486. <-term
  487. } else {
  488. s.logger.Printf("No listener active.")
  489. }
  490. s.logger.Printf("Server stopped.")
  491. }