From 232340f5e3ebe61787021bebea01fd755513c72b Mon Sep 17 00:00:00 2001 From: David Svantesson Date: Sat, 2 Nov 2019 08:37:05 +0100 Subject: [PATCH] Prevent upload (overwrite) of lfs locked file (#8769) * Check if file is locked on upload file commit. * Better user message if file is locked. * Check lfs lock before creating temporary repository. fix some errors. * move lines * Add comment that enabled setting is checked. --- models/error.go | 17 +++++++++++++++++ modules/repofiles/upload.go | 24 +++++++++++++++++------- options/locale/locale_en-US.ini | 1 + routers/repo/editor.go | 6 +++++- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/models/error.go b/models/error.go index 995617e83..505df2886 100644 --- a/models/error.go +++ b/models/error.go @@ -647,6 +647,23 @@ func (err ErrLFSLockAlreadyExist) Error() string { return fmt.Sprintf("lfs lock already exists [rid: %d, path: %s]", err.RepoID, err.Path) } +// ErrLFSFileLocked represents a "LFSFileLocked" kind of error. +type ErrLFSFileLocked struct { + RepoID int64 + Path string + UserName string +} + +// IsErrLFSFileLocked checks if an error is a ErrLFSFileLocked. +func IsErrLFSFileLocked(err error) bool { + _, ok := err.(ErrLFSFileLocked) + return ok +} + +func (err ErrLFSFileLocked) Error() string { + return fmt.Sprintf("File is lfs locked [repo: %d, locked by: %s, path: %s]", err.RepoID, err.UserName, err.Path) +} + // __________ .__ __ // \______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. // | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | diff --git a/modules/repofiles/upload.go b/modules/repofiles/upload.go index a2e7cc927..eb1379560 100644 --- a/modules/repofiles/upload.go +++ b/modules/repofiles/upload.go @@ -55,6 +55,23 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep return fmt.Errorf("GetUploadsByUUIDs [uuids: %v]: %v", opts.Files, err) } + names := make([]string, len(uploads)) + infos := make([]uploadInfo, len(uploads)) + for i, upload := range uploads { + // Check file is not lfs locked, will return nil if lock setting not enabled + filepath := path.Join(opts.TreePath, upload.Name) + lfsLock, err := repo.GetTreePathLock(filepath) + if err != nil { + return err + } + if lfsLock != nil && lfsLock.OwnerID != doer.ID { + return models.ErrLFSFileLocked{RepoID: repo.ID, Path: filepath, UserName: lfsLock.Owner.Name} + } + + names[i] = upload.Name + infos[i] = uploadInfo{upload: upload} + } + t, err := NewTemporaryUploadRepository(repo) if err != nil { return err @@ -67,13 +84,6 @@ func UploadRepoFiles(repo *models.Repository, doer *models.User, opts *UploadRep return err } - names := make([]string, len(uploads)) - infos := make([]uploadInfo, len(uploads)) - for i, upload := range uploads { - names[i] = upload.Name - infos[i] = uploadInfo{upload: upload} - } - var filename2attribute2info map[string]map[string]string if setting.LFS.StartServer { filename2attribute2info, err = t.CheckAttribute("filter", names...) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4d1af69db..794d78c6f 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -742,6 +742,7 @@ editor.no_changes_to_show = There are no changes to show. editor.fail_to_update_file = Failed to update/create file '%s' with error: %v editor.add_subdir = Add a directory… editor.unable_to_upload_files = Failed to upload files to '%s' with error: %v +editor.upload_file_is_locked = File '%s' is locked by %s. editor.upload_files_to_dir = Upload files to '%s' editor.cannot_commit_to_protected_branch = Cannot commit to protected branch '%s'. diff --git a/routers/repo/editor.go b/routers/repo/editor.go index d4a7dab07..763429f8c 100644 --- a/routers/repo/editor.go +++ b/routers/repo/editor.go @@ -585,7 +585,11 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) { Files: form.Files, }); err != nil { ctx.Data["Err_TreePath"] = true - ctx.RenderWithErr(ctx.Tr("repo.editor.unable_to_upload_files", form.TreePath, err), tplUploadFile, &form) + if models.IsErrLFSFileLocked(err) { + ctx.RenderWithErr(ctx.Tr("repo.editor.upload_file_is_locked", err.(models.ErrLFSFileLocked).Path, err.(models.ErrLFSFileLocked).UserName), tplUploadFile, &form) + } else { + ctx.RenderWithErr(ctx.Tr("repo.editor.unable_to_upload_files", form.TreePath, err), tplUploadFile, &form) + } return }