mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-11-04 05:27:04 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			214 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package ctrl
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"github.com/gorilla/mux"
 | 
						|
	. "github.com/mickael-kerjean/filestash/server/common"
 | 
						|
	"github.com/mickael-kerjean/filestash/server/model"
 | 
						|
	"net/http"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
func ShareList(ctx *App, res http.ResponseWriter, req *http.Request) {
 | 
						|
	path, err := PathBuilder(ctx, req.URL.Query().Get("path"))
 | 
						|
	if err != nil {
 | 
						|
		SendErrorResult(res, err)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	listOfSharedLinks, err := model.ShareList(
 | 
						|
		GenerateID(ctx.Session),
 | 
						|
		path,
 | 
						|
	)
 | 
						|
	if err != nil {
 | 
						|
		Log.Debug("share::list '%s'", err.Error())
 | 
						|
		SendErrorResult(res, err)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	for i := 0; i < len(listOfSharedLinks); i++ {
 | 
						|
		listOfSharedLinks[i].Path = "/" + strings.TrimPrefix(listOfSharedLinks[i].Path, path)
 | 
						|
	}
 | 
						|
	SendSuccessResults(res, listOfSharedLinks)
 | 
						|
}
 | 
						|
 | 
						|
func ShareUpsert(ctx *App, res http.ResponseWriter, req *http.Request) {
 | 
						|
	share_id := mux.Vars(req)["share"]
 | 
						|
	if share_id == "private" {
 | 
						|
		Log.Debug("share::upsert 'private'")
 | 
						|
		SendErrorResult(res, ErrNotValid)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	s := Share{
 | 
						|
		Id: share_id,
 | 
						|
		Auth: func() string {
 | 
						|
			if ctx.Share.Id == "" {
 | 
						|
				str := ""
 | 
						|
				index := 0
 | 
						|
				for {
 | 
						|
					cookie, err := req.Cookie(CookieName(index))
 | 
						|
					if err != nil {
 | 
						|
						break
 | 
						|
					}
 | 
						|
					index++
 | 
						|
					str += cookie.Value
 | 
						|
				}
 | 
						|
				return str
 | 
						|
			}
 | 
						|
			return ctx.Share.Auth
 | 
						|
		}(),
 | 
						|
		Backend: func() string {
 | 
						|
			if ctx.Share.Id == "" {
 | 
						|
				return GenerateID(ctx.Session)
 | 
						|
			}
 | 
						|
			return ctx.Share.Backend
 | 
						|
		}(),
 | 
						|
		Path: func() string {
 | 
						|
			leftPath := "/"
 | 
						|
			rightPath := strings.TrimPrefix(NewStringFromInterface(ctx.Body["path"]), "/")
 | 
						|
			if ctx.Share.Id != "" {
 | 
						|
				leftPath = ctx.Share.Path
 | 
						|
			} else {
 | 
						|
				if ctx.Session["path"] != "" {
 | 
						|
					leftPath = ctx.Session["path"]
 | 
						|
				}
 | 
						|
			}
 | 
						|
			return leftPath + rightPath
 | 
						|
		}(),
 | 
						|
		Password:     NewStringpFromInterface(ctx.Body["password"]),
 | 
						|
		Users:        NewStringpFromInterface(ctx.Body["users"]),
 | 
						|
		Expire:       NewInt64pFromInterface(ctx.Body["expire"]),
 | 
						|
		Url:          NewStringpFromInterface(ctx.Body["url"]),
 | 
						|
		CanManageOwn: NewBoolFromInterface(ctx.Body["can_manage_own"]),
 | 
						|
		CanShare:     NewBoolFromInterface(ctx.Body["can_share"]),
 | 
						|
		CanRead:      NewBoolFromInterface(ctx.Body["can_read"]),
 | 
						|
		CanWrite:     NewBoolFromInterface(ctx.Body["can_write"]),
 | 
						|
		CanUpload:    NewBoolFromInterface(ctx.Body["can_upload"]),
 | 
						|
	}
 | 
						|
	if err := model.ShareUpsert(&s); err != nil {
 | 
						|
		Log.Debug("share::upsert '%s'", err.Error())
 | 
						|
		SendErrorResult(res, err)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	SendSuccessResult(res, nil)
 | 
						|
}
 | 
						|
 | 
						|
func ShareDelete(ctx *App, res http.ResponseWriter, req *http.Request) {
 | 
						|
	share_target := mux.Vars(req)["share"]
 | 
						|
	if err := model.ShareDelete(share_target); err != nil {
 | 
						|
		Log.Debug("share::delete '%s'", err.Error())
 | 
						|
		SendErrorResult(res, err)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	SendSuccessResult(res, nil)
 | 
						|
}
 | 
						|
 | 
						|
func ShareVerifyProof(ctx *App, res http.ResponseWriter, req *http.Request) {
 | 
						|
	var submittedProof model.Proof
 | 
						|
	var verifiedProof []model.Proof
 | 
						|
	var requiredProof []model.Proof
 | 
						|
	var remainingProof []model.Proof
 | 
						|
	var s Share
 | 
						|
	var err error
 | 
						|
 | 
						|
	// 1) initialise the current context
 | 
						|
	share_id := mux.Vars(req)["share"]
 | 
						|
	s, err = model.ShareGet(share_id)
 | 
						|
	if err != nil {
 | 
						|
		Log.Debug("share::verify::init '%s'", err.Error())
 | 
						|
		SendErrorResult(res, err)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	submittedProof = model.Proof{
 | 
						|
		Key:   fmt.Sprint(ctx.Body["type"]),
 | 
						|
		Value: fmt.Sprint(ctx.Body["value"]),
 | 
						|
	}
 | 
						|
	verifiedProof = model.ShareProofGetAlreadyVerified(req)
 | 
						|
	requiredProof = model.ShareProofGetRequired(s)
 | 
						|
 | 
						|
	// 2) validate the current context
 | 
						|
	if len(verifiedProof) > 20 || len(requiredProof) > 20 {
 | 
						|
		http.SetCookie(res, &http.Cookie{
 | 
						|
			Name:   COOKIE_NAME_PROOF,
 | 
						|
			Value:  "",
 | 
						|
			MaxAge: -1,
 | 
						|
			Path:   COOKIE_PATH,
 | 
						|
		})
 | 
						|
		Log.Debug("share::verify::validate 'proof issue' len(verifiedProof)[%d] len(requiredProof)[%d]", len(verifiedProof), len(requiredProof))
 | 
						|
		SendErrorResult(res, ErrNotValid)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if err := s.IsValid(); err != nil {
 | 
						|
		Log.Debug("share::verify::validate '%s'", err.Error())
 | 
						|
		SendErrorResult(res, err)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	// 3) process the proof sent by the user
 | 
						|
	submittedProof, err = model.ShareProofVerifier(s, submittedProof)
 | 
						|
	if err != nil {
 | 
						|
		Log.Debug("share::verify::process '%s'", err.Error())
 | 
						|
		submittedProof.Error = NewString(err.Error())
 | 
						|
		SendSuccessResult(res, submittedProof)
 | 
						|
		return
 | 
						|
	}
 | 
						|
	if submittedProof.Key == "code" {
 | 
						|
		submittedProof.Value = ""
 | 
						|
		submittedProof.Message = NewString("We've sent you a message with a verification code")
 | 
						|
		SendSuccessResult(res, submittedProof)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if submittedProof.Key != "" {
 | 
						|
		submittedProof.Id = Hash(submittedProof.Key+"::"+submittedProof.Value, 20)
 | 
						|
		alreadyExist := false
 | 
						|
		for i := 0; i < len(verifiedProof); i++ {
 | 
						|
			if verifiedProof[i].Id == submittedProof.Id {
 | 
						|
				alreadyExist = true
 | 
						|
				break
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if alreadyExist == false {
 | 
						|
			verifiedProof = append(verifiedProof, submittedProof)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// 4) Find remaining proofs: requiredProof - verifiedProof
 | 
						|
	remainingProof = model.ShareProofCalculateRemainings(requiredProof, verifiedProof)
 | 
						|
 | 
						|
	// 5) persist proofs in client cookie
 | 
						|
	cookie := http.Cookie{
 | 
						|
		Name: COOKIE_NAME_PROOF,
 | 
						|
		Value: func(p []model.Proof) string {
 | 
						|
			j, _ := json.Marshal(p)
 | 
						|
			str, _ := EncryptString(SECRET_KEY_DERIVATE_FOR_PROOF, string(j))
 | 
						|
			return str
 | 
						|
		}(verifiedProof),
 | 
						|
		Path:     COOKIE_PATH,
 | 
						|
		MaxAge:   60 * 60 * 24 * 30,
 | 
						|
		HttpOnly: true,
 | 
						|
		SameSite: http.SameSiteNoneMode,
 | 
						|
		Secure:   true,
 | 
						|
	}
 | 
						|
	http.SetCookie(res, &cookie)
 | 
						|
 | 
						|
	if len(remainingProof) > 0 {
 | 
						|
		SendSuccessResult(res, remainingProof[0])
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	SendSuccessResult(res, struct {
 | 
						|
		Id        string `json:"id"`
 | 
						|
		Path      string `json:"path"`
 | 
						|
		CanRead   bool   `json:"can_read"`
 | 
						|
		CanWrite  bool   `json:"can_write"`
 | 
						|
		CanUpload bool   `json:"can_upload"`
 | 
						|
	}{
 | 
						|
		Id:        s.Id,
 | 
						|
		Path:      s.Path,
 | 
						|
		CanRead:   s.CanRead,
 | 
						|
		CanWrite:  s.CanWrite,
 | 
						|
		CanUpload: s.CanUpload,
 | 
						|
	})
 | 
						|
}
 |