github.com/GregorioDiStefano/go-file-storage@v0.0.0-20161001105139-5707ab351525/controllers/download.go (about) 1 package controller 2 3 import ( 4 "encoding/json" 5 "io/ioutil" 6 "net/http" 7 "net/url" 8 "time" 9 10 "github.com/GregorioDiStefano/go-file-storage/log" 11 "github.com/GregorioDiStefano/go-file-storage/models" 12 "github.com/GregorioDiStefano/go-file-storage/utils" 13 "github.com/gin-gonic/gin" 14 ) 15 16 type Download struct { 17 CaptchaSecret string 18 MaxDownloads int 19 } 20 21 func NewDownloader(captchaSecret string, maxDownloads int) *Download { 22 return &Download{captchaSecret, maxDownloads} 23 } 24 25 func (download Download) checkCaptcha(gRecaptchaResponse string) bool { 26 secret := utils.Config.GetString("CAPTCHA_SECRET") 27 response := gRecaptchaResponse 28 29 postURL := "https://www.google.com/recaptcha/api/siteverify" 30 31 resp, _ := http.PostForm(postURL, 32 url.Values{"secret": {secret}, "response": {response}}) 33 34 if respPayload, err := ioutil.ReadAll(resp.Body); err == nil { 35 jsonMap := make(map[string]interface{}) 36 e := json.Unmarshal(respPayload, &jsonMap) 37 38 success, ok := jsonMap["success"] 39 40 if e != nil || !ok { 41 return false 42 } else if success == true { 43 return true 44 } 45 } 46 return false 47 } 48 49 func (download Download) DownloadFile(c *gin.Context) { 50 key := c.Param("key") 51 fn := c.Param("filename") 52 googleCaptchaCode := c.Query("g-recaptcha-response") 53 54 log.WithFields(log.Fields{"key": key, "fn": fn}).Info("Incoming download.") 55 56 sf := models.DB.ReadStoredFile(key) 57 58 if !models.DB.DoesKeyExist(key) || sf == nil || sf.Deleted || sf.FileName != fn { 59 if sf == nil { 60 log.WithFields(log.Fields{"key": key, "fn": fn}).Error("Download failed since key doesn't exist in database") 61 } else { 62 log.WithFields(log.Fields{"key": key, "fn": fn, "delete": sf.Deleted}).Error("Download failed") 63 } 64 sendError(c, "Invalid filename, key, or file is deleted") 65 return 66 } 67 68 sf.LastAccess = time.Now().UTC() 69 70 //if file has been download too many times, show this page, with requires a captcha to be solved 71 if sf.Downloads >= download.MaxDownloads && !download.checkCaptcha(googleCaptchaCode) { 72 if utils.IsWebBrowser(c.Request.Header.Get("User-Agent")) { 73 c.HTML(http.StatusOK, "download.tmpl", gin.H{ 74 "filename": fn, 75 }) 76 return 77 } 78 79 log.WithFields(log.Fields{"key": key, "filename": fn}).Info("File downloads exceeded - not web browser") 80 sendError(c, "This file has been download too many times, visit the URL with a Browser") 81 return 82 } 83 84 sf.Downloads = sf.Downloads + 1 85 log.WithFields(log.Fields{"key": key, "filename": fn}).Info("Downloads set to ", sf.Downloads) 86 models.DB.WriteStoredFile(*sf) 87 88 c.Header("Cache-Control", "no-cache, no-store, must-revalidate") 89 90 ip := c.ClientIP() 91 log.WithFields(log.Fields{"ip": ip, "key": key, "fn": fn}).Info("S3 download started.") 92 c.Redirect(http.StatusMovedPermanently, utils.GetS3SignedURL(sf.Key, sf.FileName, ip)) 93 return 94 }