139 lines
3.3 KiB
Go
139 lines
3.3 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"net/http"
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
"time"
|
||
|
|
||
|
"github.com/andreimarcu/linx-server/backends"
|
||
|
"github.com/flosch/pongo2"
|
||
|
"github.com/zenazn/goji/web"
|
||
|
)
|
||
|
|
||
|
type accessKeySource int
|
||
|
|
||
|
const (
|
||
|
accessKeySourceNone accessKeySource = iota
|
||
|
accessKeySourceCookie
|
||
|
accessKeySourceHeader
|
||
|
accessKeySourceForm
|
||
|
accessKeySourceQuery
|
||
|
)
|
||
|
|
||
|
const accessKeyHeaderName = "Linx-Access-Key"
|
||
|
const accessKeyParamName = "access_key"
|
||
|
|
||
|
var (
|
||
|
errInvalidAccessKey = errors.New("invalid access key")
|
||
|
|
||
|
cliUserAgentRe = regexp.MustCompile("(?i)(lib)?curl|wget")
|
||
|
)
|
||
|
|
||
|
func checkAccessKey(r *http.Request, metadata *backends.Metadata) (accessKeySource, error) {
|
||
|
key := metadata.AccessKey
|
||
|
if key == "" {
|
||
|
return accessKeySourceNone, nil
|
||
|
}
|
||
|
|
||
|
cookieKey, err := r.Cookie(accessKeyHeaderName)
|
||
|
if err == nil {
|
||
|
if cookieKey.Value == key {
|
||
|
return accessKeySourceCookie, nil
|
||
|
}
|
||
|
return accessKeySourceCookie, errInvalidAccessKey
|
||
|
}
|
||
|
|
||
|
headerKey := r.Header.Get(accessKeyHeaderName)
|
||
|
if headerKey == key {
|
||
|
return accessKeySourceHeader, nil
|
||
|
} else if headerKey != "" {
|
||
|
return accessKeySourceHeader, errInvalidAccessKey
|
||
|
}
|
||
|
|
||
|
formKey := r.PostFormValue(accessKeyParamName)
|
||
|
if formKey == key {
|
||
|
return accessKeySourceForm, nil
|
||
|
} else if formKey != "" {
|
||
|
return accessKeySourceForm, errInvalidAccessKey
|
||
|
}
|
||
|
|
||
|
queryKey := r.URL.Query().Get(accessKeyParamName)
|
||
|
if queryKey == key {
|
||
|
return accessKeySourceQuery, nil
|
||
|
} else if formKey != "" {
|
||
|
return accessKeySourceQuery, errInvalidAccessKey
|
||
|
}
|
||
|
|
||
|
return accessKeySourceNone, errInvalidAccessKey
|
||
|
}
|
||
|
|
||
|
func setAccessKeyCookies(w http.ResponseWriter, domain, fileName, value string, expires time.Time) {
|
||
|
cookie := http.Cookie{
|
||
|
Name: accessKeyHeaderName,
|
||
|
Value: value,
|
||
|
HttpOnly: true,
|
||
|
Domain: domain,
|
||
|
Expires: expires,
|
||
|
}
|
||
|
|
||
|
cookie.Path = Config.sitePath + fileName
|
||
|
http.SetCookie(w, &cookie)
|
||
|
|
||
|
cookie.Path = Config.sitePath + Config.selifPath + fileName
|
||
|
http.SetCookie(w, &cookie)
|
||
|
}
|
||
|
|
||
|
func fileAccessHandler(c web.C, w http.ResponseWriter, r *http.Request) {
|
||
|
if !Config.noDirectAgents && cliUserAgentRe.MatchString(r.Header.Get("User-Agent")) && !strings.EqualFold("application/json", r.Header.Get("Accept")) {
|
||
|
fileServeHandler(c, w, r)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
fileName := c.URLParams["name"]
|
||
|
|
||
|
metadata, err := checkFile(fileName)
|
||
|
if err == backends.NotFoundErr {
|
||
|
notFoundHandler(c, w, r)
|
||
|
return
|
||
|
} else if err != nil {
|
||
|
oopsHandler(c, w, r, RespAUTO, "Corrupt metadata.")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if src, err := checkAccessKey(r, &metadata); err != nil {
|
||
|
// remove invalid cookie
|
||
|
if src == accessKeySourceCookie {
|
||
|
setAccessKeyCookies(w, getSiteURL(r), fileName, "", time.Unix(0, 0))
|
||
|
}
|
||
|
|
||
|
if strings.EqualFold("application/json", r.Header.Get("Accept")) {
|
||
|
dec := json.NewEncoder(w)
|
||
|
_ = dec.Encode(map[string]string{
|
||
|
"error": errInvalidAccessKey.Error(),
|
||
|
})
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
_ = renderTemplate(Templates["access.html"], pongo2.Context{
|
||
|
"filename": fileName,
|
||
|
"accesspath": fileName,
|
||
|
}, r, w)
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if metadata.AccessKey != "" {
|
||
|
var expiry time.Time
|
||
|
if Config.accessKeyCookieExpiry != 0 {
|
||
|
expiry = time.Now().Add(time.Duration(Config.accessKeyCookieExpiry) * time.Second)
|
||
|
}
|
||
|
setAccessKeyCookies(w, getSiteURL(r), fileName, metadata.AccessKey, expiry)
|
||
|
}
|
||
|
|
||
|
fileDisplayHandler(c, w, r, fileName, metadata)
|
||
|
}
|