* Test if object is accessible. * Added more logging. Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
This commit is contained in:
		
							parent
							
								
									3ac1f35349
								
							
						
					
					
						commit
						cbe3ca5d0b
					
				
					 2 changed files with 60 additions and 19 deletions
				
			
		|  | @ -254,6 +254,10 @@ func TestAPILFSBatch(t *testing.T) { | |||
| 			assert.NoError(t, err) | ||||
| 			assert.True(t, exist) | ||||
| 
 | ||||
| 			repo2 := createLFSTestRepository(t, "batch2") | ||||
| 			content := []byte("dummy0") | ||||
| 			storeObjectInRepo(t, repo2.ID, &content) | ||||
| 
 | ||||
| 			meta, err := repo.GetLFSMetaObjectByOid(p.Oid) | ||||
| 			assert.Nil(t, meta) | ||||
| 			assert.Equal(t, models.ErrLFSObjectNotExist, err) | ||||
|  | @ -359,13 +363,19 @@ func TestAPILFSUpload(t *testing.T) { | |||
| 		assert.Nil(t, meta) | ||||
| 		assert.Equal(t, models.ErrLFSObjectNotExist, err) | ||||
| 
 | ||||
| 		req := newRequest(t, p, "") | ||||
| 		t.Run("InvalidAccess", func(t *testing.T) { | ||||
| 			req := newRequest(t, p, "invalid") | ||||
| 			session.MakeRequest(t, req, http.StatusUnprocessableEntity) | ||||
| 		}) | ||||
| 
 | ||||
| 		session.MakeRequest(t, req, http.StatusOK) | ||||
| 		t.Run("ValidAccess", func(t *testing.T) { | ||||
| 			req := newRequest(t, p, "dummy5") | ||||
| 
 | ||||
| 		meta, err = repo.GetLFSMetaObjectByOid(p.Oid) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.NotNil(t, meta) | ||||
| 			session.MakeRequest(t, req, http.StatusOK) | ||||
| 			meta, err = repo.GetLFSMetaObjectByOid(p.Oid) | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.NotNil(t, meta) | ||||
| 		}) | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("MetaAlreadyExists", func(t *testing.T) { | ||||
|  |  | |||
|  | @ -5,7 +5,9 @@ | |||
| package lfs | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/sha256" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/hex" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
|  | @ -213,14 +215,22 @@ func BatchHandler(ctx *context.Context) { | |||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			if exists { | ||||
| 				if meta == nil { | ||||
| 			if exists && meta == nil { | ||||
| 				accessible, err := models.LFSObjectAccessible(ctx.User, p.Oid) | ||||
| 				if err != nil { | ||||
| 					log.Error("Unable to check if LFS MetaObject [%s] is accessible. Error: %v", p.Oid, err) | ||||
| 					writeStatus(ctx, http.StatusInternalServerError) | ||||
| 					return | ||||
| 				} | ||||
| 				if accessible { | ||||
| 					_, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: p, RepositoryID: repository.ID}) | ||||
| 					if err != nil { | ||||
| 						log.Error("Unable to create LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, err) | ||||
| 						writeStatus(ctx, http.StatusInternalServerError) | ||||
| 						return | ||||
| 					} | ||||
| 				} else { | ||||
| 					exists = false | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
|  | @ -270,29 +280,50 @@ func UploadHandler(ctx *context.Context) { | |||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	meta, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: p, RepositoryID: repository.ID}) | ||||
| 	if err != nil { | ||||
| 		log.Error("Unable to create LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, err) | ||||
| 		writeStatus(ctx, http.StatusInternalServerError) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	contentStore := lfs_module.NewContentStore() | ||||
| 
 | ||||
| 	exists, err := contentStore.Exists(p) | ||||
| 	if err != nil { | ||||
| 		log.Error("Unable to check if LFS OID[%s] exist. Error: %v", p.Oid, err) | ||||
| 		writeStatus(ctx, http.StatusInternalServerError) | ||||
| 		return | ||||
| 	} | ||||
| 	if meta.Existing || exists { | ||||
| 		ctx.Resp.WriteHeader(http.StatusOK) | ||||
| 		return | ||||
| 
 | ||||
| 	uploadOrVerify := func() error { | ||||
| 		if exists { | ||||
| 			accessible, err := models.LFSObjectAccessible(ctx.User, p.Oid) | ||||
| 			if err != nil { | ||||
| 				log.Error("Unable to check if LFS MetaObject [%s] is accessible. Error: %v", p.Oid, err) | ||||
| 				return err | ||||
| 			} | ||||
| 			if !accessible { | ||||
| 				// The file exists but the user has no access to it.
 | ||||
| 				// The upload gets verified by hashing and size comparison to prove access to it.
 | ||||
| 				hash := sha256.New() | ||||
| 				written, err := io.Copy(hash, ctx.Req.Body) | ||||
| 				if err != nil { | ||||
| 					log.Error("Error creating hash. Error: %v", err) | ||||
| 					return err | ||||
| 				} | ||||
| 
 | ||||
| 				if written != p.Size { | ||||
| 					return lfs_module.ErrSizeMismatch | ||||
| 				} | ||||
| 				if hex.EncodeToString(hash.Sum(nil)) != p.Oid { | ||||
| 					return lfs_module.ErrHashMismatch | ||||
| 				} | ||||
| 			} | ||||
| 		} else if err := contentStore.Put(p, ctx.Req.Body); err != nil { | ||||
| 			log.Error("Error putting LFS MetaObject [%s] into content store. Error: %v", p.Oid, err) | ||||
| 			return err | ||||
| 		} | ||||
| 		_, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: p, RepositoryID: repository.ID}) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	defer ctx.Req.Body.Close() | ||||
| 	if err := contentStore.Put(meta.Pointer, ctx.Req.Body); err != nil { | ||||
| 	if err := uploadOrVerify(); err != nil { | ||||
| 		if errors.Is(err, lfs_module.ErrSizeMismatch) || errors.Is(err, lfs_module.ErrHashMismatch) { | ||||
| 			log.Error("Upload does not match LFS MetaObject [%s]. Error: %v", p.Oid, err) | ||||
| 			writeStatusMessage(ctx, http.StatusUnprocessableEntity, err.Error()) | ||||
| 		} else { | ||||
| 			writeStatus(ctx, http.StatusInternalServerError) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue