mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
add authorizing fileId write access
need to secure upload/update/delete for benchmark/filer/mount need to add secure grpc
This commit is contained in:
parent
4ff4a147b2
commit
215cd27b37
|
@ -10,7 +10,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdScaffold = &Command{
|
var cmdScaffold = &Command{
|
||||||
UsageLine: "scaffold [filer]",
|
UsageLine: "scaffold -config=[filer|notification|replication|security]",
|
||||||
Short: "generate basic configuration files",
|
Short: "generate basic configuration files",
|
||||||
Long: `Generate filer.toml with all possible configurations for you to customize.
|
Long: `Generate filer.toml with all possible configurations for you to customize.
|
||||||
|
|
||||||
|
@ -244,10 +244,14 @@ directory = "/" # destination directory
|
||||||
`
|
`
|
||||||
|
|
||||||
SECURITY_TOML_EXAMPLE = `
|
SECURITY_TOML_EXAMPLE = `
|
||||||
|
# Put this file to one of the location, with descending priority
|
||||||
|
# ./security.toml
|
||||||
|
# $HOME/.seaweedfs/security.toml
|
||||||
|
# /etc/seaweedfs/security.toml
|
||||||
# this file is read by master, volume server, and filer
|
# this file is read by master, volume server, and filer
|
||||||
|
|
||||||
[jwt]
|
[jwt.signing]
|
||||||
signing_key = ""
|
key = ""
|
||||||
|
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
|
@ -41,21 +41,21 @@ https://github.com/pkieltyka/jwtauth/blob/master/jwtauth.go
|
||||||
|
|
||||||
*/
|
*/
|
||||||
type Guard struct {
|
type Guard struct {
|
||||||
whiteList []string
|
whiteList []string
|
||||||
SecretKey SigningKey
|
SigningKey SigningKey
|
||||||
|
|
||||||
isActive bool
|
isActive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGuard(whiteList []string, secretKey string) *Guard {
|
func NewGuard(whiteList []string, signingKey string) *Guard {
|
||||||
g := &Guard{whiteList: whiteList, SecretKey: SigningKey(secretKey)}
|
g := &Guard{whiteList: whiteList, SigningKey: SigningKey(signingKey)}
|
||||||
g.isActive = len(g.whiteList) != 0 || len(g.SecretKey) != 0
|
g.isActive = len(g.whiteList) != 0 || len(g.SigningKey) != 0
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Guard) WhiteList(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
func (g *Guard) WhiteList(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
||||||
if !g.isActive {
|
if !g.isActive {
|
||||||
//if no security needed, just skip all checkings
|
//if no security needed, just skip all checking
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -67,20 +67,6 @@ func (g *Guard) WhiteList(f func(w http.ResponseWriter, r *http.Request)) func(w
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Guard) Secure(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if !g.isActive {
|
|
||||||
//if no security needed, just skip all checkings
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if err := g.checkJwt(w, r); err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f(w, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetActualRemoteHost(r *http.Request) (host string, err error) {
|
func GetActualRemoteHost(r *http.Request) (host string, err error) {
|
||||||
host = r.Header.Get("HTTP_X_FORWARDED_FOR")
|
host = r.Header.Get("HTTP_X_FORWARDED_FOR")
|
||||||
if host == "" {
|
if host == "" {
|
||||||
|
@ -130,33 +116,3 @@ func (g *Guard) checkWhiteList(w http.ResponseWriter, r *http.Request) error {
|
||||||
glog.V(0).Infof("Not in whitelist: %s", r.RemoteAddr)
|
glog.V(0).Infof("Not in whitelist: %s", r.RemoteAddr)
|
||||||
return fmt.Errorf("Not in whitelis: %s", r.RemoteAddr)
|
return fmt.Errorf("Not in whitelis: %s", r.RemoteAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Guard) checkJwt(w http.ResponseWriter, r *http.Request) error {
|
|
||||||
if g.checkWhiteList(w, r) == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(g.SecretKey) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenStr := GetJwt(r)
|
|
||||||
|
|
||||||
if tokenStr == "" {
|
|
||||||
return ErrUnauthorized
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the token
|
|
||||||
token, err := DecodeJwt(g.SecretKey, tokenStr)
|
|
||||||
if err != nil {
|
|
||||||
glog.V(1).Infof("Token verification error from %s: %v", r.RemoteAddr, err)
|
|
||||||
return ErrUnauthorized
|
|
||||||
}
|
|
||||||
if !token.Valid {
|
|
||||||
glog.V(1).Infof("Token invliad from %s: %v", r.RemoteAddr, tokenStr)
|
|
||||||
return ErrUnauthorized
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.V(1).Infof("No permission from %s", r.RemoteAddr)
|
|
||||||
return fmt.Errorf("No write permission from %s", r.RemoteAddr)
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package security
|
package security
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -11,21 +12,28 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type EncodedJwt string
|
type EncodedJwt string
|
||||||
type SigningKey string
|
type SigningKey []byte
|
||||||
|
|
||||||
|
type SeaweedFileIdClaims struct {
|
||||||
|
Fid string `json:"fid"`
|
||||||
|
jwt.StandardClaims
|
||||||
|
}
|
||||||
|
|
||||||
func GenJwt(signingKey SigningKey, fileId string) EncodedJwt {
|
func GenJwt(signingKey SigningKey, fileId string) EncodedJwt {
|
||||||
if signingKey == "" {
|
if len(signingKey) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
t := jwt.New(jwt.GetSigningMethod("HS256"))
|
claims := SeaweedFileIdClaims{
|
||||||
t.Claims = &jwt.StandardClaims{
|
fileId,
|
||||||
ExpiresAt: time.Now().Add(time.Second * 10).Unix(),
|
jwt.StandardClaims{
|
||||||
Subject: fileId,
|
ExpiresAt: time.Now().Add(time.Second * 10).Unix(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
encoded, e := t.SignedString(signingKey)
|
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
encoded, e := t.SignedString([]byte(signingKey))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
glog.V(0).Infof("Failed to sign claims: %v", t.Claims)
|
glog.V(0).Infof("Failed to sign claims %+v: %v", t.Claims, e)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return EncodedJwt(encoded)
|
return EncodedJwt(encoded)
|
||||||
|
@ -44,31 +52,15 @@ func GetJwt(r *http.Request) EncodedJwt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get token from cookie
|
|
||||||
if tokenStr == "" {
|
|
||||||
cookie, err := r.Cookie("jwt")
|
|
||||||
if err == nil {
|
|
||||||
tokenStr = cookie.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return EncodedJwt(tokenStr)
|
return EncodedJwt(tokenStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EncodeJwt(signingKey SigningKey, claims *jwt.StandardClaims) (EncodedJwt, error) {
|
|
||||||
if signingKey == "" {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
t := jwt.New(jwt.GetSigningMethod("HS256"))
|
|
||||||
t.Claims = claims
|
|
||||||
encoded, e := t.SignedString(signingKey)
|
|
||||||
return EncodedJwt(encoded), e
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeJwt(signingKey SigningKey, tokenString EncodedJwt) (token *jwt.Token, err error) {
|
func DecodeJwt(signingKey SigningKey, tokenString EncodedJwt) (token *jwt.Token, err error) {
|
||||||
// check exp, nbf
|
// check exp, nbf
|
||||||
return jwt.Parse(string(tokenString), func(token *jwt.Token) (interface{}, error) {
|
return jwt.Parse(string(tokenString), func(token *jwt.Token) (interface{}, error) {
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("unknown token method")
|
||||||
|
}
|
||||||
return signingKey, nil
|
return signingKey, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/topology"
|
"github.com/chrislusf/seaweedfs/weed/topology"
|
||||||
"github.com/chrislusf/seaweedfs/weed/util"
|
"github.com/chrislusf/seaweedfs/weed/util"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MasterServer struct {
|
type MasterServer struct {
|
||||||
|
@ -47,6 +48,10 @@ func NewMasterServer(r *mux.Router, port int, metaFolder string,
|
||||||
whiteList []string,
|
whiteList []string,
|
||||||
) *MasterServer {
|
) *MasterServer {
|
||||||
|
|
||||||
|
LoadConfiguration("security", false)
|
||||||
|
v := viper.GetViper()
|
||||||
|
signingKey := v.GetString("jwt.signing.key")
|
||||||
|
|
||||||
var preallocateSize int64
|
var preallocateSize int64
|
||||||
if preallocate {
|
if preallocate {
|
||||||
preallocateSize = int64(volumeSizeLimitMB) * (1 << 20)
|
preallocateSize = int64(volumeSizeLimitMB) * (1 << 20)
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/chrislusf/seaweedfs/weed/operation"
|
"github.com/chrislusf/seaweedfs/weed/operation"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/stats"
|
"github.com/chrislusf/seaweedfs/weed/stats"
|
||||||
"github.com/chrislusf/seaweedfs/weed/storage"
|
"github.com/chrislusf/seaweedfs/weed/storage"
|
||||||
)
|
)
|
||||||
|
@ -40,12 +41,23 @@ func (ms *MasterServer) lookupVolumeId(vids []string, collection string) (volume
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes one volumeId only, can not do batch lookup
|
// If "fileId" is provided, this returns the fileId location and a JWT to update or delete the file.
|
||||||
|
// If "volumeId" is provided, this only returns the volumeId location
|
||||||
func (ms *MasterServer) dirLookupHandler(w http.ResponseWriter, r *http.Request) {
|
func (ms *MasterServer) dirLookupHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
vid := r.FormValue("volumeId")
|
vid := r.FormValue("volumeId")
|
||||||
commaSep := strings.Index(vid, ",")
|
if vid != "" {
|
||||||
if commaSep > 0 {
|
// backward compatible
|
||||||
vid = vid[0:commaSep]
|
commaSep := strings.Index(vid, ",")
|
||||||
|
if commaSep > 0 {
|
||||||
|
vid = vid[0:commaSep]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileId := r.FormValue("fileId")
|
||||||
|
if fileId != "" {
|
||||||
|
commaSep := strings.Index(fileId, ",")
|
||||||
|
if commaSep > 0 {
|
||||||
|
vid = fileId[0:commaSep]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vids := []string{vid}
|
vids := []string{vid}
|
||||||
collection := r.FormValue("collection") //optional, but can be faster if too many collections
|
collection := r.FormValue("collection") //optional, but can be faster if too many collections
|
||||||
|
@ -54,6 +66,8 @@ func (ms *MasterServer) dirLookupHandler(w http.ResponseWriter, r *http.Request)
|
||||||
httpStatus := http.StatusOK
|
httpStatus := http.StatusOK
|
||||||
if location.Error != "" {
|
if location.Error != "" {
|
||||||
httpStatus = http.StatusNotFound
|
httpStatus = http.StatusNotFound
|
||||||
|
} else {
|
||||||
|
ms.maybeAddJwtAuthorization(w, fileId)
|
||||||
}
|
}
|
||||||
writeJsonQuiet(w, r, httpStatus, location)
|
writeJsonQuiet(w, r, httpStatus, location)
|
||||||
}
|
}
|
||||||
|
@ -88,8 +102,17 @@ func (ms *MasterServer) dirAssignHandler(w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
fid, count, dn, err := ms.Topo.PickForWrite(requestedCount, option)
|
fid, count, dn, err := ms.Topo.PickForWrite(requestedCount, option)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
ms.maybeAddJwtAuthorization(w, fid)
|
||||||
writeJsonQuiet(w, r, http.StatusOK, operation.AssignResult{Fid: fid, Url: dn.Url(), PublicUrl: dn.PublicUrl, Count: count})
|
writeJsonQuiet(w, r, http.StatusOK, operation.AssignResult{Fid: fid, Url: dn.Url(), PublicUrl: dn.PublicUrl, Count: count})
|
||||||
} else {
|
} else {
|
||||||
writeJsonQuiet(w, r, http.StatusNotAcceptable, operation.AssignResult{Error: err.Error()})
|
writeJsonQuiet(w, r, http.StatusNotAcceptable, operation.AssignResult{Error: err.Error()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ms *MasterServer) maybeAddJwtAuthorization(w http.ResponseWriter, fileId string) {
|
||||||
|
encodedJwt := security.GenJwt(ms.guard.SigningKey, fileId)
|
||||||
|
if encodedJwt == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Authorization", "BEARER "+string(encodedJwt))
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
"github.com/chrislusf/seaweedfs/weed/security"
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/storage"
|
"github.com/chrislusf/seaweedfs/weed/storage"
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VolumeServer struct {
|
type VolumeServer struct {
|
||||||
|
@ -31,6 +32,12 @@ func NewVolumeServer(adminMux, publicMux *http.ServeMux, ip string,
|
||||||
whiteList []string,
|
whiteList []string,
|
||||||
fixJpgOrientation bool,
|
fixJpgOrientation bool,
|
||||||
readRedirect bool) *VolumeServer {
|
readRedirect bool) *VolumeServer {
|
||||||
|
|
||||||
|
LoadConfiguration("security", false)
|
||||||
|
v := viper.GetViper()
|
||||||
|
signingKey := v.GetString("jwt.signing.key")
|
||||||
|
enableUiAccess := v.GetBool("access.ui")
|
||||||
|
|
||||||
vs := &VolumeServer{
|
vs := &VolumeServer{
|
||||||
pulseSeconds: pulseSeconds,
|
pulseSeconds: pulseSeconds,
|
||||||
dataCenter: dataCenter,
|
dataCenter: dataCenter,
|
||||||
|
@ -42,14 +49,17 @@ func NewVolumeServer(adminMux, publicMux *http.ServeMux, ip string,
|
||||||
vs.MasterNodes = masterNodes
|
vs.MasterNodes = masterNodes
|
||||||
vs.store = storage.NewStore(port, ip, publicUrl, folders, maxCounts, vs.needleMapKind)
|
vs.store = storage.NewStore(port, ip, publicUrl, folders, maxCounts, vs.needleMapKind)
|
||||||
|
|
||||||
vs.guard = security.NewGuard(whiteList, "")
|
vs.guard = security.NewGuard(whiteList, signingKey)
|
||||||
|
|
||||||
handleStaticResources(adminMux)
|
handleStaticResources(adminMux)
|
||||||
adminMux.HandleFunc("/ui/index.html", vs.uiStatusHandler)
|
if signingKey == "" || enableUiAccess {
|
||||||
adminMux.HandleFunc("/status", vs.guard.WhiteList(vs.statusHandler))
|
// only expose the volume server details for safe environments
|
||||||
adminMux.HandleFunc("/stats/counter", vs.guard.WhiteList(statsCounterHandler))
|
adminMux.HandleFunc("/ui/index.html", vs.uiStatusHandler)
|
||||||
adminMux.HandleFunc("/stats/memory", vs.guard.WhiteList(statsMemoryHandler))
|
adminMux.HandleFunc("/status", vs.guard.WhiteList(vs.statusHandler))
|
||||||
adminMux.HandleFunc("/stats/disk", vs.guard.WhiteList(vs.statsDiskHandler))
|
adminMux.HandleFunc("/stats/counter", vs.guard.WhiteList(statsCounterHandler))
|
||||||
|
adminMux.HandleFunc("/stats/memory", vs.guard.WhiteList(statsMemoryHandler))
|
||||||
|
adminMux.HandleFunc("/stats/disk", vs.guard.WhiteList(vs.statsDiskHandler))
|
||||||
|
}
|
||||||
adminMux.HandleFunc("/", vs.privateStoreHandler)
|
adminMux.HandleFunc("/", vs.privateStoreHandler)
|
||||||
if publicMux != adminMux {
|
if publicMux != adminMux {
|
||||||
// separated admin and public port
|
// separated admin and public port
|
||||||
|
@ -69,5 +79,5 @@ func (vs *VolumeServer) Shutdown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vs *VolumeServer) jwt(fileId string) security.EncodedJwt {
|
func (vs *VolumeServer) jwt(fileId string) security.EncodedJwt {
|
||||||
return security.GenJwt(vs.guard.SecretKey, fileId)
|
return security.GenJwt(vs.guard.SigningKey, fileId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package weed_server
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||||
|
"github.com/chrislusf/seaweedfs/weed/security"
|
||||||
"github.com/chrislusf/seaweedfs/weed/stats"
|
"github.com/chrislusf/seaweedfs/weed/stats"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,3 +47,32 @@ func (vs *VolumeServer) publicReadOnlyHandler(w http.ResponseWriter, r *http.Req
|
||||||
vs.GetOrHeadHandler(w, r)
|
vs.GetOrHeadHandler(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vs *VolumeServer) maybeCheckJwtAuthorization(r *http.Request, vid, fid string) bool {
|
||||||
|
|
||||||
|
if len(vs.guard.SigningKey) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenStr := security.GetJwt(r)
|
||||||
|
if tokenStr == "" {
|
||||||
|
glog.V(1).Infof("missing jwt from %s", r.RemoteAddr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := security.DecodeJwt(vs.guard.SigningKey, tokenStr)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(1).Infof("jwt verification error from %s: %v", r.RemoteAddr, err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !token.Valid {
|
||||||
|
glog.V(1).Infof("jwt invalid from %s: %v", r.RemoteAddr, tokenStr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if sc, ok := token.Claims.(*security.SeaweedFileIdClaims); ok {
|
||||||
|
return sc.Fid == vid+","+fid
|
||||||
|
}
|
||||||
|
glog.V(1).Infof("unexpected jwt from %s: %v", r.RemoteAddr, tokenStr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -20,13 +20,20 @@ func (vs *VolumeServer) PostHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
writeJsonError(w, r, http.StatusBadRequest, e)
|
writeJsonError(w, r, http.StatusBadRequest, e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
vid, _, _, _, _ := parseURLPath(r.URL.Path)
|
|
||||||
|
vid, fid, _, _, _ := parseURLPath(r.URL.Path)
|
||||||
volumeId, ve := storage.NewVolumeId(vid)
|
volumeId, ve := storage.NewVolumeId(vid)
|
||||||
if ve != nil {
|
if ve != nil {
|
||||||
glog.V(0).Infoln("NewVolumeId error:", ve)
|
glog.V(0).Infoln("NewVolumeId error:", ve)
|
||||||
writeJsonError(w, r, http.StatusBadRequest, ve)
|
writeJsonError(w, r, http.StatusBadRequest, ve)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !vs.maybeCheckJwtAuthorization(r, vid, fid) {
|
||||||
|
writeJsonError(w, r, http.StatusUnauthorized, errors.New("wrong jwt"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
needle, originalSize, ne := storage.CreateNeedleFromRequest(r, vs.FixJpgOrientation)
|
needle, originalSize, ne := storage.CreateNeedleFromRequest(r, vs.FixJpgOrientation)
|
||||||
if ne != nil {
|
if ne != nil {
|
||||||
writeJsonError(w, r, http.StatusBadRequest, ne)
|
writeJsonError(w, r, http.StatusBadRequest, ne)
|
||||||
|
@ -56,6 +63,11 @@ func (vs *VolumeServer) DeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
volumeId, _ := storage.NewVolumeId(vid)
|
volumeId, _ := storage.NewVolumeId(vid)
|
||||||
n.ParsePath(fid)
|
n.ParsePath(fid)
|
||||||
|
|
||||||
|
if !vs.maybeCheckJwtAuthorization(r, vid, fid) {
|
||||||
|
writeJsonError(w, r, http.StatusUnauthorized, errors.New("wrong jwt"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// glog.V(2).Infof("volume %s deleting %s", vid, n)
|
// glog.V(2).Infof("volume %s deleting %s", vid, n)
|
||||||
|
|
||||||
cookie := n.Cookie
|
cookie := n.Cookie
|
||||||
|
|
Loading…
Reference in a new issue