Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions code/go/0chain.net/blobbercore/handler/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1109,8 +1109,8 @@ func TestHandlers_Requiring_Signature(t *testing.T) {
AddRow(alloc.Terms[0].ID, alloc.Terms[0].AllocationID),
)

mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "reference_objects"`)).
WithArgs(aa).
mock.ExpectQuery(regexp.QuoteMeta(`SELECT "id" FROM "reference_objects"`)).
WithArgs(aa, aa).
WillReturnError(gorm.ErrRecordNotFound)

mock.ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "allocation_connections" WHERE`)).
Expand Down Expand Up @@ -1490,7 +1490,7 @@ func TestHandlers_Requiring_Signature(t *testing.T) {
test.end()
}

fmt.Printf("\nResponse body: %v", test.args.w.Body.String())
fmt.Printf("\nResponse body for test %v: %v", test.name, test.args.w.Body.String())
assert.Equal(t, test.wantCode, test.args.w.Result().StatusCode)
if test.wantCode != http.StatusOK || test.wantBody != "" {
assert.Equal(t, test.wantBody, test.args.w.Body.String())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"strings"

"github.com/0chain/blobber/code/go/0chain.net/blobbercore/blobberhttp"
"github.com/0chain/blobber/code/go/0chain.net/blobbercore/stats"
Expand All @@ -23,6 +25,7 @@ import (
"github.com/0chain/blobber/code/go/0chain.net/core/common"
"github.com/0chain/blobber/code/go/0chain.net/core/encryption"
"github.com/0chain/blobber/code/go/0chain.net/core/lock"
"github.com/0chain/blobber/code/go/0chain.net/core/logging"
"github.com/0chain/blobber/code/go/0chain.net/core/node"
"github.com/0chain/gosdk/constants"

Expand Down Expand Up @@ -889,6 +892,10 @@ func (fsh *StorageHandler) CreateDir(ctx context.Context, r *http.Request) (*blo
return nil, common.NewError("duplicate_file", "File at path already exists")
}

if err := validateParentPathType(ctx, allocationID, dirPath); err != nil {
return nil, err
}

connectionID := r.FormValue("connection_id")
if connectionID == "" {
return nil, common.NewError("invalid_parameters", "Invalid connection id passed")
Expand Down Expand Up @@ -948,7 +955,21 @@ func (fsh *StorageHandler) WriteFile(ctx context.Context, r *http.Request) (*blo

allocationID := allocationObj.ID
fileOperation := getFileOperation(r)
existingFileRef := getExistingFileRef(fsh, ctx, r, allocationObj, fileOperation)
formData := getFormData(ctx, r, allocationObj, fileOperation)
var existingFileRef *reference.Ref
if formData != nil {
existingFileRef, err = reference.GetRefWithID(ctx, allocationID, formData.Path)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
logging.Logger.Error(err.Error())
return nil, common.NewError("database_error", "Got error while getting ref from database")
}

if err := validateParentPathType(ctx, allocationID, formData.Path); err != nil {
return nil, err
}

}

isCollaborator := existingFileRef != nil && reference.IsACollaborator(ctx, existingFileRef.ID, clientID)
publicKey := allocationObj.OwnerPublicKey

Expand Down Expand Up @@ -1040,15 +1061,55 @@ func getFileOperation(r *http.Request) string {
return mode
}

func getExistingFileRef(fsh *StorageHandler, ctx context.Context, r *http.Request, allocationObj *allocation.Allocation, fileOperation string) *reference.Ref {
func getFormData(ctx context.Context, r *http.Request, allocationObj *allocation.Allocation, fileOperation string) *allocation.UpdateFileChanger {
if fileOperation == constants.FileOperationInsert || fileOperation == constants.FileOperationUpdate {
var formData allocation.UpdateFileChanger
uploadMetaString := r.FormValue(getFormFieldName(fileOperation))
err := json.Unmarshal([]byte(uploadMetaString), &formData)

if err == nil {
return fsh.checkIfFileAlreadyExists(ctx, allocationObj.ID, formData.Path)
if err != nil {
return nil
}
return &formData
}
return nil
}

// validateParentPathType validates against any parent path not being directory.
func validateParentPathType(ctx context.Context, allocationID, fPath string) error {
if fPath == "" {
return nil
}

fPath = filepath.Clean(fPath)
if !filepath.IsAbs(fPath) {
return fmt.Errorf("filepath %v is not absolute path", fPath)
}
refs, err := reference.GetRefsTypeFromPaths(ctx, allocationID, getParentPaths(fPath))
if err != nil {
logging.Logger.Error(err.Error())
return common.NewError("database_error", "Got error while getting parent refs")
}

for _, ref := range refs {
if ref == nil {
continue
}
if ref.Type == reference.FILE {
return common.NewError("invalid_path", fmt.Sprintf("parent path %v is of file type", ref.Path))
}
}
return nil
}

// getParentPaths For path /a/b/c.txt, will return [/a,/a/b]
func getParentPaths(fPath string) []string {
splittedPaths := strings.Split(fPath, "/")
var paths []string

for i := 0; i < len(splittedPaths); i++ {
subPath := strings.Join(splittedPaths[0:i], "/")
paths = append(paths, subPath)
}
return paths[2:]
}
49 changes: 49 additions & 0 deletions code/go/0chain.net/blobbercore/reference/ref.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,55 @@ func GetReferenceFromLookupHash(ctx context.Context, allocationID, path_hash str
return nil, err
}

// GetRefType Select type from ref and return it
func GetRefType(ctx context.Context, allocationID, path string) (string, error) {
ref := new(Ref)
db := datastore.GetStore().GetTransaction(ctx)
err := db.Select("type").Where("allocation_id=? AND path=?", allocationID, path).First(ref).Error
if err != nil {
return "", err
}
return ref.Type, nil
}

// GetRefWithID Return Ref with only ID selected in sql query
func GetRefWithID(ctx context.Context, allocationID, path string) (*Ref, error) {
ref := new(Ref)
db := datastore.GetStore().GetTransaction(ctx)
err := db.Select("id").Where("allocation_id=? AND path=?", allocationID, path).First(ref).Error
if err != nil {
return nil, err
}
return ref, nil
}

// IsRefExist checks if ref with given path exists and returns error other than gorm.ErrRecordNotFound
func IsRefExist(ctx context.Context, allocationID, path string) (bool, error) {
db := datastore.GetStore().GetTransaction(ctx)
ref := new(Ref)
err := db.Select("path").Where("allocation_id=? AND path=?", allocationID, path).First(ref).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return false, nil
}
return false, err
}

return true, nil
}

// GetRefsTypeFromPaths Give list of paths it will return refs of respective path with only Type and Path selected in sql query
func GetRefsTypeFromPaths(ctx context.Context, allocationID string, paths []string) (refs []*Ref, err error) {
db := datastore.GetStore().GetTransaction(ctx)
db = db.Select("path", "type")
for _, p := range paths {
db = db.Or(Ref{AllocationID: allocationID, Path: p})
}

err = db.Find(&refs).Error
return
}

func GetSubDirsFromPath(p string) []string {
path := p
parent, cur := filepath.Split(path)
Expand Down