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  }