handlers.go 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  1. /*
  2. The MIT License (MIT)
  3. Copyright (c) 2014-2017 DutchCoders [https://github.com/dutchcoders/]
  4. Copyright (c) 2018-2020 Andrea Spacca.
  5. Copyright (c) 2020- Andrea Spacca and Stefan Benten.
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in
  13. all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. THE SOFTWARE.
  21. */
  22. package server
  23. import (
  24. "archive/tar"
  25. "archive/zip"
  26. "bytes"
  27. "compress/gzip"
  28. "context"
  29. "encoding/base64"
  30. "encoding/json"
  31. "errors"
  32. "fmt"
  33. "html"
  34. htmlTemplate "html/template"
  35. "io"
  36. "mime"
  37. "net"
  38. "net/http"
  39. "net/url"
  40. "os"
  41. "path"
  42. "path/filepath"
  43. "strconv"
  44. "strings"
  45. "sync"
  46. textTemplate "text/template"
  47. "time"
  48. "unicode"
  49. "github.com/ProtonMail/go-crypto/openpgp"
  50. "github.com/ProtonMail/go-crypto/openpgp/armor"
  51. "github.com/ProtonMail/go-crypto/openpgp/packet"
  52. "github.com/ProtonMail/gopenpgp/v2/constants"
  53. "github.com/dutchcoders/transfer.sh/server/storage"
  54. "github.com/tg123/go-htpasswd"
  55. "github.com/tomasen/realip"
  56. web "github.com/dutchcoders/transfer.sh-web"
  57. "github.com/gorilla/mux"
  58. "github.com/microcosm-cc/bluemonday"
  59. blackfriday "github.com/russross/blackfriday/v2"
  60. qrcode "github.com/skip2/go-qrcode"
  61. "golang.org/x/net/idna"
  62. "golang.org/x/text/runes"
  63. "golang.org/x/text/transform"
  64. "golang.org/x/text/unicode/norm"
  65. )
  66. const getPathPart = "get"
  67. var (
  68. htmlTemplates = initHTMLTemplates()
  69. textTemplates = initTextTemplates()
  70. )
  71. func stripPrefix(path string) string {
  72. return strings.Replace(path, web.Prefix+"/", "", -1)
  73. }
  74. func initTextTemplates() *textTemplate.Template {
  75. templateMap := textTemplate.FuncMap{"format": formatNumber}
  76. // Templates with functions available to them
  77. var templates = textTemplate.New("").Funcs(templateMap)
  78. return templates
  79. }
  80. func initHTMLTemplates() *htmlTemplate.Template {
  81. templateMap := htmlTemplate.FuncMap{"format": formatNumber}
  82. // Templates with functions available to them
  83. var templates = htmlTemplate.New("").Funcs(templateMap)
  84. return templates
  85. }
  86. func attachEncryptionReader(reader io.ReadCloser, password string) (io.ReadCloser, error) {
  87. if len(password) == 0 {
  88. return reader, nil
  89. }
  90. return encrypt(reader, []byte(password))
  91. }
  92. func attachDecryptionReader(reader io.ReadCloser, password string) (io.ReadCloser, error) {
  93. if len(password) == 0 {
  94. return reader, nil
  95. }
  96. return decrypt(reader, []byte(password))
  97. }
  98. func decrypt(ciphertext io.ReadCloser, password []byte) (plaintext io.ReadCloser, err error) {
  99. unarmored, err := armor.Decode(ciphertext)
  100. if err != nil {
  101. return
  102. }
  103. firstTimeCalled := true
  104. var prompt = func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
  105. if firstTimeCalled {
  106. firstTimeCalled = false
  107. return password, nil
  108. }
  109. // Re-prompt still occurs if SKESK pasrsing fails (i.e. when decrypted cipher algo is invalid).
  110. // For most (but not all) cases, inputting a wrong passwords is expected to trigger this error.
  111. return nil, errors.New("gopenpgp: wrong password in symmetric decryption")
  112. }
  113. config := &packet.Config{
  114. DefaultCipher: packet.CipherAES256,
  115. }
  116. var emptyKeyRing openpgp.EntityList
  117. md, err := openpgp.ReadMessage(unarmored.Body, emptyKeyRing, prompt, config)
  118. if err != nil {
  119. // Parsing errors when reading the message are most likely caused by incorrect password, but we cannot know for sure
  120. return
  121. }
  122. plaintext = io.NopCloser(md.UnverifiedBody)
  123. return
  124. }
  125. type encryptWrapperReader struct {
  126. plaintext io.Reader
  127. encrypt io.WriteCloser
  128. armored io.WriteCloser
  129. buffer io.ReadWriter
  130. plaintextReadZero bool
  131. }
  132. func (e *encryptWrapperReader) Read(p []byte) (n int, err error) {
  133. p2 := make([]byte, len(p))
  134. n, _ = e.plaintext.Read(p2)
  135. if n == 0 {
  136. if !e.plaintextReadZero {
  137. err = e.encrypt.Close()
  138. if err != nil {
  139. return
  140. }
  141. err = e.armored.Close()
  142. if err != nil {
  143. return
  144. }
  145. e.plaintextReadZero = true
  146. }
  147. return e.buffer.Read(p)
  148. }
  149. return e.buffer.Read(p)
  150. }
  151. func (e *encryptWrapperReader) Close() error {
  152. return nil
  153. }
  154. func NewEncryptWrapperReader(plaintext io.Reader, armored, encrypt io.WriteCloser, buffer io.ReadWriter) io.ReadCloser {
  155. return &encryptWrapperReader{
  156. plaintext: io.TeeReader(plaintext, encrypt),
  157. encrypt: encrypt,
  158. armored: armored,
  159. buffer: buffer,
  160. }
  161. }
  162. func encrypt(plaintext io.ReadCloser, password []byte) (ciphertext io.ReadCloser, err error) {
  163. bufferReadWriter := new(bytes.Buffer)
  164. armored, err := armor.Encode(bufferReadWriter, constants.PGPMessageHeader, nil)
  165. if err != nil {
  166. return
  167. }
  168. config := &packet.Config{
  169. DefaultCipher: packet.CipherAES256,
  170. Time: time.Now,
  171. }
  172. hints := &openpgp.FileHints{
  173. IsBinary: true,
  174. FileName: "",
  175. ModTime: time.Unix(time.Now().Unix(), 0),
  176. }
  177. encryptWriter, err := openpgp.SymmetricallyEncrypt(armored, password, hints, config)
  178. if err != nil {
  179. return
  180. }
  181. ciphertext = NewEncryptWrapperReader(plaintext, armored, encryptWriter, bufferReadWriter)
  182. return
  183. }
  184. func healthHandler(w http.ResponseWriter, _ *http.Request) {
  185. _, _ = w.Write([]byte("Approaching Neutral Zone, all systems normal and functioning."))
  186. }
  187. func canContainsXSS(contentType string) bool {
  188. switch {
  189. case strings.Contains(contentType, "cache-manifest"):
  190. fallthrough
  191. case strings.Contains(contentType, "html"):
  192. fallthrough
  193. case strings.Contains(contentType, "rdf"):
  194. fallthrough
  195. case strings.Contains(contentType, "vtt"):
  196. fallthrough
  197. case strings.Contains(contentType, "xml"):
  198. fallthrough
  199. case strings.Contains(contentType, "xsl"):
  200. return true
  201. case strings.Contains(contentType, "x-mixed-replace"):
  202. return true
  203. }
  204. return false
  205. }
  206. /* The preview handler will show a preview of the content for browsers (accept type text/html), and referer is not transfer.sh */
  207. func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
  208. w.Header().Set("Vary", "Range, Referer, X-Decrypt-Password")
  209. vars := mux.Vars(r)
  210. token := vars["token"]
  211. filename := vars["filename"]
  212. metadata, err := s.checkMetadata(r.Context(), token, filename, false)
  213. if err != nil {
  214. s.logger.Printf("Error metadata: %s", err.Error())
  215. http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
  216. return
  217. }
  218. contentType := metadata.ContentType
  219. contentLength, err := s.storage.Head(r.Context(), token, filename)
  220. if err != nil {
  221. http.Error(w, http.StatusText(404), 404)
  222. return
  223. }
  224. var templatePath string
  225. var content htmlTemplate.HTML
  226. switch {
  227. case strings.HasPrefix(contentType, "image/"):
  228. templatePath = "download.image.html"
  229. case strings.HasPrefix(contentType, "video/"):
  230. templatePath = "download.video.html"
  231. case strings.HasPrefix(contentType, "audio/"):
  232. templatePath = "download.audio.html"
  233. case strings.HasPrefix(contentType, "text/"):
  234. templatePath = "download.markdown.html"
  235. var reader io.ReadCloser
  236. if reader, _, err = s.storage.Get(r.Context(), token, filename, nil); err != nil {
  237. http.Error(w, err.Error(), http.StatusInternalServerError)
  238. return
  239. }
  240. var data []byte
  241. data = make([]byte, _5M)
  242. if _, err = reader.Read(data); err != io.EOF && err != nil {
  243. http.Error(w, err.Error(), http.StatusInternalServerError)
  244. return
  245. }
  246. if strings.HasPrefix(contentType, "text/x-markdown") || strings.HasPrefix(contentType, "text/markdown") {
  247. unsafe := blackfriday.Run(data)
  248. output := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
  249. content = htmlTemplate.HTML(output)
  250. } else if strings.HasPrefix(contentType, "text/plain") {
  251. content = htmlTemplate.HTML(fmt.Sprintf("<pre>%s</pre>", html.EscapeString(string(data))))
  252. } else {
  253. templatePath = "download.sandbox.html"
  254. }
  255. default:
  256. templatePath = "download.html"
  257. }
  258. relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
  259. resolvedURL := resolveURL(r, relativeURL, s.proxyPort)
  260. relativeURLGet, _ := url.Parse(path.Join(s.proxyPath, getPathPart, token, filename))
  261. resolvedURLGet := resolveURL(r, relativeURLGet, s.proxyPort)
  262. var png []byte
  263. png, err = qrcode.Encode(resolvedURL, qrcode.High, 150)
  264. if err != nil {
  265. http.Error(w, err.Error(), http.StatusInternalServerError)
  266. return
  267. }
  268. qrCode := base64.StdEncoding.EncodeToString(png)
  269. hostname := getURL(r, s.proxyPort).Host
  270. webAddress := resolveWebAddress(r, s.proxyPath, s.proxyPort)
  271. data := struct {
  272. ContentType string
  273. Content htmlTemplate.HTML
  274. Filename string
  275. URL string
  276. URLGet string
  277. URLRandomToken string
  278. Hostname string
  279. WebAddress string
  280. ContentLength uint64
  281. GAKey string
  282. UserVoiceKey string
  283. QRCode string
  284. }{
  285. contentType,
  286. content,
  287. filename,
  288. resolvedURL,
  289. resolvedURLGet,
  290. token,
  291. hostname,
  292. webAddress,
  293. contentLength,
  294. s.gaKey,
  295. s.userVoiceKey,
  296. qrCode,
  297. }
  298. if err := htmlTemplates.ExecuteTemplate(w, templatePath, data); err != nil {
  299. http.Error(w, err.Error(), http.StatusInternalServerError)
  300. return
  301. }
  302. }
  303. // this handler will output html or text, depending on the
  304. // support of the client (Accept header).
  305. func (s *Server) viewHandler(w http.ResponseWriter, r *http.Request) {
  306. // vars := mux.Vars(r)
  307. hostname := getURL(r, s.proxyPort).Host
  308. webAddress := resolveWebAddress(r, s.proxyPath, s.proxyPort)
  309. maxUploadSize := ""
  310. if s.maxUploadSize > 0 {
  311. maxUploadSize = formatSize(s.maxUploadSize)
  312. }
  313. purgeTime := ""
  314. if s.purgeDays > 0 {
  315. purgeTime = formatDurationDays(s.purgeDays)
  316. }
  317. data := struct {
  318. Hostname string
  319. WebAddress string
  320. EmailContact string
  321. GAKey string
  322. UserVoiceKey string
  323. PurgeTime string
  324. MaxUploadSize string
  325. SampleToken string
  326. SampleToken2 string
  327. }{
  328. hostname,
  329. webAddress,
  330. s.emailContact,
  331. s.gaKey,
  332. s.userVoiceKey,
  333. purgeTime,
  334. maxUploadSize,
  335. token(s.randomTokenLength),
  336. token(s.randomTokenLength),
  337. }
  338. w.Header().Set("Vary", "Accept")
  339. if acceptsHTML(r.Header) {
  340. if err := htmlTemplates.ExecuteTemplate(w, "index.html", data); err != nil {
  341. http.Error(w, err.Error(), http.StatusInternalServerError)
  342. return
  343. }
  344. } else {
  345. if err := textTemplates.ExecuteTemplate(w, "index.txt", data); err != nil {
  346. http.Error(w, err.Error(), http.StatusInternalServerError)
  347. return
  348. }
  349. }
  350. }
  351. func (s *Server) notFoundHandler(w http.ResponseWriter, _ *http.Request) {
  352. http.Error(w, http.StatusText(404), 404)
  353. }
  354. func sanitize(fileName string) string {
  355. t := transform.Chain(
  356. norm.NFD,
  357. runes.Remove(runes.In(unicode.Cc)),
  358. runes.Remove(runes.In(unicode.Cf)),
  359. runes.Remove(runes.In(unicode.Co)),
  360. runes.Remove(runes.In(unicode.Cs)),
  361. runes.Remove(runes.In(unicode.Other)),
  362. runes.Remove(runes.In(unicode.Zl)),
  363. runes.Remove(runes.In(unicode.Zp)),
  364. norm.NFC)
  365. newName, _, err := transform.String(t, fileName)
  366. if err != nil {
  367. return path.Base(fileName)
  368. }
  369. if len(newName) == 0 {
  370. newName = "_"
  371. }
  372. return path.Base(newName)
  373. }
  374. func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {
  375. if err := r.ParseMultipartForm(_24K); nil != err {
  376. s.logger.Printf("%s", err.Error())
  377. http.Error(w, "Error occurred copying to output stream", http.StatusInternalServerError)
  378. return
  379. }
  380. token := token(s.randomTokenLength)
  381. w.Header().Set("Content-Type", "text/plain")
  382. responseBody := ""
  383. for _, fHeaders := range r.MultipartForm.File {
  384. for _, fHeader := range fHeaders {
  385. filename := sanitize(fHeader.Filename)
  386. contentType := mime.TypeByExtension(filepath.Ext(fHeader.Filename))
  387. var f io.Reader
  388. var err error
  389. if f, err = fHeader.Open(); err != nil {
  390. s.logger.Printf("%s", err.Error())
  391. http.Error(w, err.Error(), http.StatusInternalServerError)
  392. return
  393. }
  394. file, err := os.CreateTemp(s.tempPath, "transfer-")
  395. defer s.cleanTmpFile(file)
  396. if err != nil {
  397. s.logger.Printf("%s", err.Error())
  398. http.Error(w, err.Error(), http.StatusInternalServerError)
  399. return
  400. }
  401. n, err := io.Copy(file, f)
  402. if err != nil {
  403. s.logger.Printf("%s", err.Error())
  404. http.Error(w, err.Error(), http.StatusInternalServerError)
  405. return
  406. }
  407. contentLength := n
  408. _, err = file.Seek(0, io.SeekStart)
  409. if err != nil {
  410. s.logger.Printf("%s", err.Error())
  411. return
  412. }
  413. if s.maxUploadSize > 0 && contentLength > s.maxUploadSize {
  414. s.logger.Print("Entity too large")
  415. http.Error(w, http.StatusText(http.StatusRequestEntityTooLarge), http.StatusRequestEntityTooLarge)
  416. return
  417. }
  418. if s.performClamavPrescan {
  419. status, err := s.performScan(file.Name())
  420. if err != nil {
  421. s.logger.Printf("%s", err.Error())
  422. http.Error(w, "Could not perform prescan", http.StatusInternalServerError)
  423. return
  424. }
  425. if status != clamavScanStatusOK {
  426. s.logger.Printf("prescan positive: %s", status)
  427. http.Error(w, "Clamav prescan found a virus", http.StatusPreconditionFailed)
  428. return
  429. }
  430. }
  431. metadata := metadataForRequest(contentType, contentLength, s.randomTokenLength, r)
  432. buffer := &bytes.Buffer{}
  433. if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
  434. s.logger.Printf("%s", err.Error())
  435. http.Error(w, "Could not encode metadata", http.StatusInternalServerError)
  436. return
  437. } else if err := s.storage.Put(r.Context(), token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
  438. s.logger.Printf("%s", err.Error())
  439. http.Error(w, "Could not save metadata", http.StatusInternalServerError)
  440. return
  441. }
  442. s.logger.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
  443. reader, err := attachEncryptionReader(file, r.Header.Get("X-Encrypt-Password"))
  444. if err != nil {
  445. http.Error(w, "Could not crypt file", http.StatusInternalServerError)
  446. return
  447. }
  448. if err = s.storage.Put(r.Context(), token, filename, reader, contentType, uint64(contentLength)); err != nil {
  449. s.logger.Printf("Backend storage error: %s", err.Error())
  450. http.Error(w, err.Error(), http.StatusInternalServerError)
  451. return
  452. }
  453. filename = url.PathEscape(filename)
  454. relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
  455. deleteURL, _ := url.Parse(path.Join(s.proxyPath, token, filename, metadata.DeletionToken))
  456. w.Header().Add("X-Url-Delete", resolveURL(r, deleteURL, s.proxyPort))
  457. responseBody += fmt.Sprintln(getURL(r, s.proxyPort).ResolveReference(relativeURL).String())
  458. }
  459. }
  460. _, err := w.Write([]byte(responseBody))
  461. if err != nil {
  462. s.logger.Printf("%s", err.Error())
  463. http.Error(w, err.Error(), http.StatusInternalServerError)
  464. }
  465. }
  466. func (s *Server) cleanTmpFile(f *os.File) {
  467. if f != nil {
  468. err := f.Close()
  469. if err != nil {
  470. s.logger.Printf("Error closing tmpfile: %s (%s)", err, f.Name())
  471. }
  472. err = os.Remove(f.Name())
  473. if err != nil {
  474. s.logger.Printf("Error removing tmpfile: %s (%s)", err, f.Name())
  475. }
  476. }
  477. }
  478. type metadata struct {
  479. // ContentType is the original uploading content type
  480. ContentType string
  481. // ContentLength is is the original uploading content length
  482. ContentLength int64
  483. // Downloads is the actual number of downloads
  484. Downloads int
  485. // MaxDownloads contains the maximum numbers of downloads
  486. MaxDownloads int
  487. // MaxDate contains the max age of the file
  488. MaxDate time.Time
  489. // DeletionToken contains the token to match against for deletion
  490. DeletionToken string
  491. // Encrypted contains if the file was encrypted
  492. Encrypted bool
  493. // DecryptedContentType is the original uploading content type
  494. DecryptedContentType string
  495. }
  496. func metadataForRequest(contentType string, contentLength int64, randomTokenLength int, r *http.Request) metadata {
  497. metadata := metadata{
  498. ContentType: strings.ToLower(contentType),
  499. ContentLength: contentLength,
  500. MaxDate: time.Time{},
  501. Downloads: 0,
  502. MaxDownloads: -1,
  503. DeletionToken: token(randomTokenLength) + token(randomTokenLength),
  504. }
  505. if v := r.Header.Get("Max-Downloads"); v == "" {
  506. } else if v, err := strconv.Atoi(v); err != nil {
  507. } else {
  508. metadata.MaxDownloads = v
  509. }
  510. if v := r.Header.Get("Max-Days"); v == "" {
  511. } else if v, err := strconv.Atoi(v); err != nil {
  512. } else {
  513. metadata.MaxDate = time.Now().Add(time.Hour * 24 * time.Duration(v))
  514. }
  515. if password := r.Header.Get("X-Encrypt-Password"); password != "" {
  516. metadata.Encrypted = true
  517. metadata.ContentType = "text/plain; charset=utf-8"
  518. metadata.DecryptedContentType = contentType
  519. } else {
  520. metadata.Encrypted = false
  521. }
  522. return metadata
  523. }
  524. func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {
  525. vars := mux.Vars(r)
  526. filename := sanitize(vars["filename"])
  527. contentLength := r.ContentLength
  528. defer storage.CloseCheck(r.Body)
  529. reader := r.Body
  530. if contentLength < 1 || s.performClamavPrescan {
  531. file, err := os.CreateTemp(s.tempPath, "transfer-")
  532. defer s.cleanTmpFile(file)
  533. if err != nil {
  534. s.logger.Printf("%s", err.Error())
  535. http.Error(w, err.Error(), http.StatusInternalServerError)
  536. return
  537. }
  538. // queue file to disk, because s3 needs content length
  539. // and clamav prescan scans a file
  540. n, err := io.Copy(file, r.Body)
  541. if err != nil {
  542. s.logger.Printf("%s", err.Error())
  543. http.Error(w, err.Error(), http.StatusInternalServerError)
  544. return
  545. }
  546. _, err = file.Seek(0, io.SeekStart)
  547. if err != nil {
  548. s.logger.Printf("%s", err.Error())
  549. http.Error(w, "Cannot reset cache file", http.StatusInternalServerError)
  550. return
  551. }
  552. contentLength = n
  553. if s.performClamavPrescan {
  554. status, err := s.performScan(file.Name())
  555. if err != nil {
  556. s.logger.Printf("%s", err.Error())
  557. http.Error(w, "Could not perform prescan", http.StatusInternalServerError)
  558. return
  559. }
  560. if status != clamavScanStatusOK {
  561. s.logger.Printf("prescan positive: %s", status)
  562. http.Error(w, "Clamav prescan found a virus", http.StatusPreconditionFailed)
  563. return
  564. }
  565. }
  566. reader = file
  567. }
  568. if s.maxUploadSize > 0 && contentLength > s.maxUploadSize {
  569. s.logger.Print("Entity too large")
  570. http.Error(w, http.StatusText(http.StatusRequestEntityTooLarge), http.StatusRequestEntityTooLarge)
  571. return
  572. }
  573. if contentLength == 0 {
  574. s.logger.Print("Empty content-length")
  575. http.Error(w, "Could not upload empty file", http.StatusBadRequest)
  576. return
  577. }
  578. contentType := mime.TypeByExtension(filepath.Ext(vars["filename"]))
  579. token := token(s.randomTokenLength)
  580. metadata := metadataForRequest(contentType, contentLength, s.randomTokenLength, r)
  581. buffer := &bytes.Buffer{}
  582. if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
  583. s.logger.Printf("%s", err.Error())
  584. http.Error(w, "Could not encode metadata", http.StatusInternalServerError)
  585. return
  586. } else if !metadata.MaxDate.IsZero() && time.Now().After(metadata.MaxDate) {
  587. s.logger.Print("Invalid MaxDate")
  588. http.Error(w, "Invalid MaxDate, make sure Max-Days is smaller than 290 years", http.StatusBadRequest)
  589. return
  590. } else if err := s.storage.Put(r.Context(), token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
  591. s.logger.Printf("%s", err.Error())
  592. http.Error(w, "Could not save metadata", http.StatusInternalServerError)
  593. return
  594. }
  595. s.logger.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType)
  596. reader, err := attachEncryptionReader(reader, r.Header.Get("X-Encrypt-Password"))
  597. if err != nil {
  598. http.Error(w, "Could not crypt file", http.StatusInternalServerError)
  599. return
  600. }
  601. if err = s.storage.Put(r.Context(), token, filename, reader, contentType, uint64(contentLength)); err != nil {
  602. s.logger.Printf("Error putting new file: %s", err.Error())
  603. http.Error(w, "Could not save file", http.StatusInternalServerError)
  604. return
  605. }
  606. // w.Statuscode = 200
  607. w.Header().Set("Content-Type", "text/plain")
  608. filename = url.PathEscape(filename)
  609. relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
  610. deleteURL, _ := url.Parse(path.Join(s.proxyPath, token, filename, metadata.DeletionToken))
  611. w.Header().Set("X-Url-Delete", resolveURL(r, deleteURL, s.proxyPort))
  612. _, _ = w.Write([]byte(resolveURL(r, relativeURL, s.proxyPort)))
  613. }
  614. func resolveURL(r *http.Request, u *url.URL, proxyPort string) string {
  615. r.URL.Path = ""
  616. return getURL(r, proxyPort).ResolveReference(u).String()
  617. }
  618. func resolveKey(key, proxyPath string) string {
  619. key = strings.TrimPrefix(key, "/")
  620. key = strings.TrimPrefix(key, proxyPath)
  621. key = strings.Replace(key, "\\", "/", -1)
  622. return key
  623. }
  624. func resolveWebAddress(r *http.Request, proxyPath string, proxyPort string) string {
  625. rUrl := getURL(r, proxyPort)
  626. var webAddress string
  627. if len(proxyPath) == 0 {
  628. webAddress = fmt.Sprintf("%s://%s/",
  629. rUrl.ResolveReference(rUrl).Scheme,
  630. rUrl.ResolveReference(rUrl).Host)
  631. } else {
  632. webAddress = fmt.Sprintf("%s://%s/%s",
  633. rUrl.ResolveReference(rUrl).Scheme,
  634. rUrl.ResolveReference(rUrl).Host,
  635. strings.TrimPrefix(proxyPath, "/"))
  636. }
  637. return webAddress
  638. }
  639. // Similar to the logic found here:
  640. // https://github.com/golang/go/blob/release-branch.go1.14/src/net/http/clone.go#L22-L33
  641. func cloneURL(u *url.URL) *url.URL {
  642. c := &url.URL{}
  643. *c = *u
  644. if u.User != nil {
  645. c.User = &url.Userinfo{}
  646. *c.User = *u.User
  647. }
  648. return c
  649. }
  650. func getURL(r *http.Request, proxyPort string) *url.URL {
  651. u := cloneURL(r.URL)
  652. if r.TLS != nil {
  653. u.Scheme = "https"
  654. } else if proto := r.Header.Get("X-Forwarded-Proto"); proto != "" {
  655. u.Scheme = proto
  656. } else {
  657. u.Scheme = "http"
  658. }
  659. host, port, err := net.SplitHostPort(r.Host)
  660. if err != nil {
  661. host = r.Host
  662. port = ""
  663. }
  664. p := idna.New(idna.ValidateForRegistration())
  665. var hostFromPunycode string
  666. hostFromPunycode, err = p.ToUnicode(host)
  667. if err == nil {
  668. host = hostFromPunycode
  669. }
  670. if len(proxyPort) != 0 {
  671. port = proxyPort
  672. }
  673. if len(port) == 0 {
  674. u.Host = host
  675. } else {
  676. if port == "80" && u.Scheme == "http" {
  677. u.Host = host
  678. } else if port == "443" && u.Scheme == "https" {
  679. u.Host = host
  680. } else {
  681. u.Host = net.JoinHostPort(host, port)
  682. }
  683. }
  684. return u
  685. }
  686. func (metadata metadata) remainingLimitHeaderValues() (remainingDownloads, remainingDays string) {
  687. if metadata.MaxDate.IsZero() {
  688. remainingDays = "n/a"
  689. } else {
  690. timeDifference := time.Until(metadata.MaxDate)
  691. remainingDays = strconv.Itoa(int(timeDifference.Hours()/24) + 1)
  692. }
  693. if metadata.MaxDownloads == -1 {
  694. remainingDownloads = "n/a"
  695. } else {
  696. remainingDownloads = strconv.Itoa(metadata.MaxDownloads - metadata.Downloads)
  697. }
  698. return remainingDownloads, remainingDays
  699. }
  700. func (s *Server) lock(token, filename string) {
  701. key := path.Join(token, filename)
  702. lock, _ := s.locks.LoadOrStore(key, &sync.Mutex{})
  703. lock.(*sync.Mutex).Lock()
  704. }
  705. func (s *Server) unlock(token, filename string) {
  706. key := path.Join(token, filename)
  707. lock, _ := s.locks.LoadOrStore(key, &sync.Mutex{})
  708. lock.(*sync.Mutex).Unlock()
  709. }
  710. func (s *Server) checkMetadata(ctx context.Context, token, filename string, increaseDownload bool) (metadata, error) {
  711. s.lock(token, filename)
  712. defer s.unlock(token, filename)
  713. var metadata metadata
  714. r, _, err := s.storage.Get(ctx, token, fmt.Sprintf("%s.metadata", filename), nil)
  715. defer storage.CloseCheck(r)
  716. if err != nil {
  717. return metadata, err
  718. }
  719. if err := json.NewDecoder(r).Decode(&metadata); err != nil {
  720. return metadata, err
  721. } else if metadata.MaxDownloads != -1 && metadata.Downloads >= metadata.MaxDownloads {
  722. return metadata, errors.New("maxDownloads expired")
  723. } else if !metadata.MaxDate.IsZero() && time.Now().After(metadata.MaxDate) {
  724. return metadata, errors.New("maxDate expired")
  725. } else if metadata.MaxDownloads != -1 && increaseDownload {
  726. // todo(nl5887): mutex?
  727. // update number of downloads
  728. metadata.Downloads++
  729. buffer := &bytes.Buffer{}
  730. if err := json.NewEncoder(buffer).Encode(metadata); err != nil {
  731. return metadata, errors.New("could not encode metadata")
  732. } else if err := s.storage.Put(ctx, token, fmt.Sprintf("%s.metadata", filename), buffer, "text/json", uint64(buffer.Len())); err != nil {
  733. return metadata, errors.New("could not save metadata")
  734. }
  735. }
  736. return metadata, nil
  737. }
  738. func (s *Server) checkDeletionToken(ctx context.Context, deletionToken, token, filename string) error {
  739. s.lock(token, filename)
  740. defer s.unlock(token, filename)
  741. var metadata metadata
  742. r, _, err := s.storage.Get(ctx, token, fmt.Sprintf("%s.metadata", filename), nil)
  743. defer storage.CloseCheck(r)
  744. if s.storage.IsNotExist(err) {
  745. return errors.New("metadata doesn't exist")
  746. } else if err != nil {
  747. return err
  748. }
  749. if err := json.NewDecoder(r).Decode(&metadata); err != nil {
  750. return err
  751. } else if metadata.DeletionToken != deletionToken {
  752. return errors.New("deletion token doesn't match")
  753. }
  754. return nil
  755. }
  756. func (s *Server) purgeHandler() {
  757. ticker := time.NewTicker(s.purgeInterval)
  758. go func() {
  759. for {
  760. <-ticker.C
  761. err := s.storage.Purge(context.TODO(), s.purgeDays)
  762. if err != nil {
  763. s.logger.Printf("error cleaning up expired files: %v", err)
  764. }
  765. }
  766. }()
  767. }
  768. func (s *Server) deleteHandler(w http.ResponseWriter, r *http.Request) {
  769. vars := mux.Vars(r)
  770. token := vars["token"]
  771. filename := vars["filename"]
  772. deletionToken := vars["deletionToken"]
  773. if err := s.checkDeletionToken(r.Context(), deletionToken, token, filename); err != nil {
  774. s.logger.Printf("Error metadata: %s", err.Error())
  775. http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
  776. return
  777. }
  778. err := s.storage.Delete(r.Context(), token, filename)
  779. if s.storage.IsNotExist(err) {
  780. http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
  781. return
  782. } else if err != nil {
  783. s.logger.Printf("%s", err.Error())
  784. http.Error(w, "Could not delete file.", http.StatusInternalServerError)
  785. return
  786. }
  787. }
  788. func (s *Server) zipHandler(w http.ResponseWriter, r *http.Request) {
  789. vars := mux.Vars(r)
  790. files := vars["files"]
  791. zipfilename := fmt.Sprintf("transfersh-%d.zip", uint16(time.Now().UnixNano()))
  792. w.Header().Set("Content-Type", "application/zip")
  793. commonHeader(w, zipfilename)
  794. zw := zip.NewWriter(w)
  795. for _, key := range strings.Split(files, ",") {
  796. key = resolveKey(key, s.proxyPath)
  797. token := strings.Split(key, "/")[0]
  798. filename := sanitize(strings.Split(key, "/")[1])
  799. if _, err := s.checkMetadata(r.Context(), token, filename, true); err != nil {
  800. s.logger.Printf("Error metadata: %s", err.Error())
  801. continue
  802. }
  803. reader, _, err := s.storage.Get(r.Context(), token, filename, nil)
  804. defer storage.CloseCheck(reader)
  805. if err != nil {
  806. if s.storage.IsNotExist(err) {
  807. http.Error(w, "File not found", 404)
  808. return
  809. }
  810. s.logger.Printf("%s", err.Error())
  811. http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
  812. return
  813. }
  814. header := &zip.FileHeader{
  815. Name: strings.Split(key, "/")[1],
  816. Method: zip.Store,
  817. Modified: time.Now().UTC(),
  818. }
  819. fw, err := zw.CreateHeader(header)
  820. if err != nil {
  821. s.logger.Printf("%s", err.Error())
  822. http.Error(w, "Internal server error.", http.StatusInternalServerError)
  823. return
  824. }
  825. if _, err = io.Copy(fw, reader); err != nil {
  826. s.logger.Printf("%s", err.Error())
  827. http.Error(w, "Internal server error.", http.StatusInternalServerError)
  828. return
  829. }
  830. }
  831. if err := zw.Close(); err != nil {
  832. s.logger.Printf("%s", err.Error())
  833. http.Error(w, "Internal server error.", http.StatusInternalServerError)
  834. return
  835. }
  836. }
  837. func (s *Server) tarGzHandler(w http.ResponseWriter, r *http.Request) {
  838. vars := mux.Vars(r)
  839. files := vars["files"]
  840. tarfilename := fmt.Sprintf("transfersh-%d.tar.gz", uint16(time.Now().UnixNano()))
  841. w.Header().Set("Content-Type", "application/x-gzip")
  842. commonHeader(w, tarfilename)
  843. gw := gzip.NewWriter(w)
  844. defer storage.CloseCheck(gw)
  845. zw := tar.NewWriter(gw)
  846. defer storage.CloseCheck(zw)
  847. for _, key := range strings.Split(files, ",") {
  848. key = resolveKey(key, s.proxyPath)
  849. token := strings.Split(key, "/")[0]
  850. filename := sanitize(strings.Split(key, "/")[1])
  851. if _, err := s.checkMetadata(r.Context(), token, filename, true); err != nil {
  852. s.logger.Printf("Error metadata: %s", err.Error())
  853. continue
  854. }
  855. reader, contentLength, err := s.storage.Get(r.Context(), token, filename, nil)
  856. defer storage.CloseCheck(reader)
  857. if err != nil {
  858. if s.storage.IsNotExist(err) {
  859. http.Error(w, "File not found", 404)
  860. return
  861. }
  862. s.logger.Printf("%s", err.Error())
  863. http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
  864. return
  865. }
  866. header := &tar.Header{
  867. Name: strings.Split(key, "/")[1],
  868. Size: int64(contentLength),
  869. }
  870. err = zw.WriteHeader(header)
  871. if err != nil {
  872. s.logger.Printf("%s", err.Error())
  873. http.Error(w, "Internal server error.", http.StatusInternalServerError)
  874. return
  875. }
  876. if _, err = io.Copy(zw, reader); err != nil {
  877. s.logger.Printf("%s", err.Error())
  878. http.Error(w, "Internal server error.", http.StatusInternalServerError)
  879. return
  880. }
  881. }
  882. }
  883. func (s *Server) tarHandler(w http.ResponseWriter, r *http.Request) {
  884. vars := mux.Vars(r)
  885. files := vars["files"]
  886. tarfilename := fmt.Sprintf("transfersh-%d.tar", uint16(time.Now().UnixNano()))
  887. w.Header().Set("Content-Type", "application/x-tar")
  888. commonHeader(w, tarfilename)
  889. zw := tar.NewWriter(w)
  890. defer storage.CloseCheck(zw)
  891. for _, key := range strings.Split(files, ",") {
  892. key = resolveKey(key, s.proxyPath)
  893. token := strings.Split(key, "/")[0]
  894. filename := strings.Split(key, "/")[1]
  895. if _, err := s.checkMetadata(r.Context(), token, filename, true); err != nil {
  896. s.logger.Printf("Error metadata: %s", err.Error())
  897. continue
  898. }
  899. reader, contentLength, err := s.storage.Get(r.Context(), token, filename, nil)
  900. defer storage.CloseCheck(reader)
  901. if err != nil {
  902. if s.storage.IsNotExist(err) {
  903. http.Error(w, "File not found", 404)
  904. return
  905. }
  906. s.logger.Printf("%s", err.Error())
  907. http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
  908. return
  909. }
  910. header := &tar.Header{
  911. Name: strings.Split(key, "/")[1],
  912. Size: int64(contentLength),
  913. }
  914. err = zw.WriteHeader(header)
  915. if err != nil {
  916. s.logger.Printf("%s", err.Error())
  917. http.Error(w, "Internal server error.", http.StatusInternalServerError)
  918. return
  919. }
  920. if _, err = io.Copy(zw, reader); err != nil {
  921. s.logger.Printf("%s", err.Error())
  922. http.Error(w, "Internal server error.", http.StatusInternalServerError)
  923. return
  924. }
  925. }
  926. }
  927. func (s *Server) headHandler(w http.ResponseWriter, r *http.Request) {
  928. vars := mux.Vars(r)
  929. token := vars["token"]
  930. filename := vars["filename"]
  931. metadata, err := s.checkMetadata(r.Context(), token, filename, false)
  932. if err != nil {
  933. s.logger.Printf("Error metadata: %s", err.Error())
  934. http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
  935. return
  936. }
  937. contentType := metadata.ContentType
  938. contentLength, err := s.storage.Head(r.Context(), token, filename)
  939. if s.storage.IsNotExist(err) {
  940. http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
  941. return
  942. } else if err != nil {
  943. s.logger.Printf("%s", err.Error())
  944. http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
  945. return
  946. }
  947. remainingDownloads, remainingDays := metadata.remainingLimitHeaderValues()
  948. w.Header().Set("Content-Type", contentType)
  949. w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
  950. w.Header().Set("Connection", "close")
  951. w.Header().Set("X-Remaining-Downloads", remainingDownloads)
  952. w.Header().Set("X-Remaining-Days", remainingDays)
  953. w.Header().Set("Vary", "Range, Referer, X-Decrypt-Password")
  954. if s.storage.IsRangeSupported() {
  955. w.Header().Set("Accept-Ranges", "bytes")
  956. }
  957. }
  958. func (s *Server) getHandler(w http.ResponseWriter, r *http.Request) {
  959. vars := mux.Vars(r)
  960. action := vars["action"]
  961. token := vars["token"]
  962. filename := vars["filename"]
  963. metadata, err := s.checkMetadata(r.Context(), token, filename, true)
  964. if err != nil {
  965. s.logger.Printf("Error metadata: %s", err.Error())
  966. http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
  967. return
  968. }
  969. var rng *storage.Range
  970. if r.Header.Get("Range") != "" {
  971. rng = storage.ParseRange(r.Header.Get("Range"))
  972. }
  973. contentType := metadata.ContentType
  974. reader, contentLength, err := s.storage.Get(r.Context(), token, filename, rng)
  975. defer storage.CloseCheck(reader)
  976. if s.storage.IsNotExist(err) {
  977. http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
  978. return
  979. } else if err != nil {
  980. s.logger.Printf("%s", err.Error())
  981. http.Error(w, "Could not retrieve file.", http.StatusInternalServerError)
  982. return
  983. }
  984. if rng != nil {
  985. cr := rng.ContentRange()
  986. if cr != "" {
  987. w.Header().Set("Accept-Ranges", "bytes")
  988. w.Header().Set("Content-Range", cr)
  989. if rng.Limit > 0 {
  990. reader = io.NopCloser(io.LimitReader(reader, int64(rng.Limit)))
  991. }
  992. }
  993. }
  994. var disposition string
  995. if action == "inline" {
  996. disposition = "inline"
  997. /*
  998. metadata.ContentType is unable to determine the type of the content,
  999. So add text/plain in this case to fix XSS related issues/
  1000. */
  1001. if strings.TrimSpace(contentType) == "" {
  1002. contentType = "text/plain; charset=utf-8"
  1003. }
  1004. } else {
  1005. disposition = "attachment"
  1006. }
  1007. remainingDownloads, remainingDays := metadata.remainingLimitHeaderValues()
  1008. w.Header().Set("Content-Disposition", fmt.Sprintf(`%s; filename="%s"`, disposition, filename))
  1009. w.Header().Set("Connection", "keep-alive")
  1010. w.Header().Set("Cache-Control", "no-store")
  1011. w.Header().Set("X-Remaining-Downloads", remainingDownloads)
  1012. w.Header().Set("X-Remaining-Days", remainingDays)
  1013. password := r.Header.Get("X-Decrypt-Password")
  1014. reader, err = attachDecryptionReader(reader, password)
  1015. if err != nil {
  1016. http.Error(w, "Could not decrypt file", http.StatusInternalServerError)
  1017. return
  1018. }
  1019. if metadata.Encrypted && len(password) > 0 {
  1020. contentType = metadata.DecryptedContentType
  1021. contentLength = uint64(metadata.ContentLength)
  1022. }
  1023. w.Header().Set("Content-Type", contentType)
  1024. w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10))
  1025. w.Header().Set("Vary", "Range, Referer, X-Decrypt-Password")
  1026. if rng != nil && rng.ContentRange() != "" {
  1027. w.WriteHeader(http.StatusPartialContent)
  1028. }
  1029. if disposition == "inline" && canContainsXSS(contentType) {
  1030. reader = io.NopCloser(bluemonday.UGCPolicy().SanitizeReader(reader))
  1031. }
  1032. if _, err = io.Copy(w, reader); err != nil {
  1033. s.logger.Printf("%s", err.Error())
  1034. http.Error(w, "Error occurred copying to output stream", http.StatusInternalServerError)
  1035. return
  1036. }
  1037. }
  1038. func commonHeader(w http.ResponseWriter, filename string) {
  1039. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
  1040. w.Header().Set("Connection", "close")
  1041. w.Header().Set("Cache-Control", "no-store")
  1042. }
  1043. // RedirectHandler handles redirect
  1044. func (s *Server) RedirectHandler(h http.Handler) http.HandlerFunc {
  1045. return func(w http.ResponseWriter, r *http.Request) {
  1046. if !s.forceHTTPS {
  1047. // we don't want to enforce https
  1048. } else if r.URL.Path == "/health.html" {
  1049. // health check url won't redirect
  1050. } else if strings.HasSuffix(ipAddrFromRemoteAddr(r.Host), ".onion") {
  1051. // .onion addresses cannot get a valid certificate, so don't redirect
  1052. } else if r.Header.Get("X-Forwarded-Proto") == "https" {
  1053. } else if r.TLS != nil {
  1054. } else {
  1055. u := getURL(r, s.proxyPort)
  1056. u.Scheme = "https"
  1057. if len(s.proxyPort) == 0 && len(s.TLSListenerString) > 0 {
  1058. _, port, err := net.SplitHostPort(s.TLSListenerString)
  1059. if err != nil || port == "443" {
  1060. port = ""
  1061. }
  1062. if len(port) > 0 {
  1063. u.Host = net.JoinHostPort(u.Hostname(), port)
  1064. } else {
  1065. u.Host = u.Hostname()
  1066. }
  1067. }
  1068. http.Redirect(w, r, u.String(), http.StatusPermanentRedirect)
  1069. return
  1070. }
  1071. h.ServeHTTP(w, r)
  1072. }
  1073. }
  1074. // LoveHandler Create a log handler for every request it receives.
  1075. func LoveHandler(h http.Handler) http.HandlerFunc {
  1076. return func(w http.ResponseWriter, r *http.Request) {
  1077. w.Header().Set("x-made-with", "<3 by DutchCoders")
  1078. w.Header().Set("x-served-by", "Proudly served by DutchCoders")
  1079. w.Header().Set("server", "Transfer.sh HTTP Server")
  1080. h.ServeHTTP(w, r)
  1081. }
  1082. }
  1083. func ipFilterHandler(h http.Handler, ipFilterOptions *IPFilterOptions) http.HandlerFunc {
  1084. return func(w http.ResponseWriter, r *http.Request) {
  1085. if ipFilterOptions == nil {
  1086. h.ServeHTTP(w, r)
  1087. } else {
  1088. WrapIPFilter(h, ipFilterOptions).ServeHTTP(w, r)
  1089. }
  1090. }
  1091. }
  1092. func (s *Server) basicAuthHandler(h http.Handler) http.HandlerFunc {
  1093. return func(w http.ResponseWriter, r *http.Request) {
  1094. if s.authUser == "" && s.authPass == "" && s.authHtpasswd == "" {
  1095. h.ServeHTTP(w, r)
  1096. return
  1097. }
  1098. if s.htpasswdFile == nil && s.authHtpasswd != "" {
  1099. htpasswdFile, err := htpasswd.New(s.authHtpasswd, htpasswd.DefaultSystems, nil)
  1100. if err != nil {
  1101. http.Error(w, err.Error(), http.StatusInternalServerError)
  1102. return
  1103. }
  1104. s.htpasswdFile = htpasswdFile
  1105. }
  1106. if s.authIPFilter == nil && s.authIPFilterOptions != nil {
  1107. s.authIPFilter = newIPFilter(s.authIPFilterOptions)
  1108. }
  1109. w.Header().Set("WWW-Authenticate", "Basic realm=\"Restricted\"")
  1110. var authorized bool
  1111. if s.authIPFilter != nil {
  1112. remoteIP := realip.FromRequest(r)
  1113. authorized = s.authIPFilter.Allowed(remoteIP)
  1114. }
  1115. username, password, authOK := r.BasicAuth()
  1116. if !authOK && !authorized {
  1117. http.Error(w, "Not authorized", http.StatusUnauthorized)
  1118. return
  1119. }
  1120. if !authorized && username == s.authUser && password == s.authPass {
  1121. authorized = true
  1122. }
  1123. if !authorized && s.htpasswdFile != nil {
  1124. authorized = s.htpasswdFile.Match(username, password)
  1125. }
  1126. if !authorized {
  1127. http.Error(w, "Not authorized", http.StatusUnauthorized)
  1128. return
  1129. }
  1130. h.ServeHTTP(w, r)
  1131. }
  1132. }