* 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.NoError(t, err) | ||||||
| 			assert.True(t, exist) | 			assert.True(t, exist) | ||||||
| 
 | 
 | ||||||
|  | 			repo2 := createLFSTestRepository(t, "batch2") | ||||||
|  | 			content := []byte("dummy0") | ||||||
|  | 			storeObjectInRepo(t, repo2.ID, &content) | ||||||
|  | 
 | ||||||
| 			meta, err := repo.GetLFSMetaObjectByOid(p.Oid) | 			meta, err := repo.GetLFSMetaObjectByOid(p.Oid) | ||||||
| 			assert.Nil(t, meta) | 			assert.Nil(t, meta) | ||||||
| 			assert.Equal(t, models.ErrLFSObjectNotExist, err) | 			assert.Equal(t, models.ErrLFSObjectNotExist, err) | ||||||
|  | @ -359,14 +363,20 @@ func TestAPILFSUpload(t *testing.T) { | ||||||
| 		assert.Nil(t, meta) | 		assert.Nil(t, meta) | ||||||
| 		assert.Equal(t, models.ErrLFSObjectNotExist, err) | 		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) | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		t.Run("ValidAccess", func(t *testing.T) { | ||||||
|  | 			req := newRequest(t, p, "dummy5") | ||||||
| 
 | 
 | ||||||
| 			session.MakeRequest(t, req, http.StatusOK) | 			session.MakeRequest(t, req, http.StatusOK) | ||||||
| 
 |  | ||||||
| 			meta, err = repo.GetLFSMetaObjectByOid(p.Oid) | 			meta, err = repo.GetLFSMetaObjectByOid(p.Oid) | ||||||
| 			assert.NoError(t, err) | 			assert.NoError(t, err) | ||||||
| 			assert.NotNil(t, meta) | 			assert.NotNil(t, meta) | ||||||
| 		}) | 		}) | ||||||
|  | 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("MetaAlreadyExists", func(t *testing.T) { | 	t.Run("MetaAlreadyExists", func(t *testing.T) { | ||||||
| 		defer PrintCurrentTest(t)() | 		defer PrintCurrentTest(t)() | ||||||
|  |  | ||||||
|  | @ -5,7 +5,9 @@ | ||||||
| package lfs | package lfs | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"crypto/sha256" | ||||||
| 	"encoding/base64" | 	"encoding/base64" | ||||||
|  | 	"encoding/hex" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
|  | @ -213,14 +215,22 @@ func BatchHandler(ctx *context.Context) { | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if exists { | 			if exists && meta == nil { | ||||||
| 				if 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}) | 					_, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: p, RepositoryID: repository.ID}) | ||||||
| 					if err != nil { | 					if err != nil { | ||||||
| 						log.Error("Unable to create LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, err) | 						log.Error("Unable to create LFS MetaObject [%s] for %s/%s. Error: %v", p.Oid, rc.User, rc.Repo, err) | ||||||
| 						writeStatus(ctx, http.StatusInternalServerError) | 						writeStatus(ctx, http.StatusInternalServerError) | ||||||
| 						return | 						return | ||||||
| 					} | 					} | ||||||
|  | 				} else { | ||||||
|  | 					exists = false | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | @ -270,29 +280,50 @@ func UploadHandler(ctx *context.Context) { | ||||||
| 		return | 		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() | 	contentStore := lfs_module.NewContentStore() | ||||||
| 
 |  | ||||||
| 	exists, err := contentStore.Exists(p) | 	exists, err := contentStore.Exists(p) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Error("Unable to check if LFS OID[%s] exist. Error: %v", p.Oid, err) | 		log.Error("Unable to check if LFS OID[%s] exist. Error: %v", p.Oid, err) | ||||||
| 		writeStatus(ctx, http.StatusInternalServerError) | 		writeStatus(ctx, http.StatusInternalServerError) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if meta.Existing || exists { | 
 | ||||||
| 		ctx.Resp.WriteHeader(http.StatusOK) | 	uploadOrVerify := func() error { | ||||||
| 		return | 		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() | 	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) { | 		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()) | 			writeStatusMessage(ctx, http.StatusUnprocessableEntity, err.Error()) | ||||||
| 		} else { | 		} else { | ||||||
| 			writeStatus(ctx, http.StatusInternalServerError) | 			writeStatus(ctx, http.StatusInternalServerError) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue