summaryrefslogtreecommitdiffstats
path: root/modules/lfs
diff options
context:
space:
mode:
authorLauris BH <lauris@nix.lv>2017-11-08 15:04:19 +0200
committerGitHub <noreply@github.com>2017-11-08 15:04:19 +0200
commitba2e0240c60873679ebfce6fc7c961b0328f706b (patch)
tree5cedd7b620bdf453cb4efe35642f726c9e43b707 /modules/lfs
parent61f5c2250353d5a4e51f50e356e8d9f193c509fd (diff)
downloadgitea-ba2e0240c60873679ebfce6fc7c961b0328f706b.tar.gz
gitea-ba2e0240c60873679ebfce6fc7c961b0328f706b.zip
Add LFS object verification step after upload (#2868)
* Add LFS object verification step after upload * Fix file verification condition and small refactor * Fix URLs * Remove newline and return status 422 on failed verification * Better error hadling
Diffstat (limited to 'modules/lfs')
-rw-r--r--modules/lfs/content_store.go17
-rw-r--r--modules/lfs/server.go48
2 files changed, 63 insertions, 2 deletions
diff --git a/modules/lfs/content_store.go b/modules/lfs/content_store.go
index 3e1b2f345b..895b51b8ba 100644
--- a/modules/lfs/content_store.go
+++ b/modules/lfs/content_store.go
@@ -1,13 +1,14 @@
package lfs
import (
- "code.gitea.io/gitea/models"
"crypto/sha256"
"encoding/hex"
"errors"
"io"
"os"
"path/filepath"
+
+ "code.gitea.io/gitea/models"
)
var (
@@ -82,6 +83,20 @@ func (s *ContentStore) Exists(meta *models.LFSMetaObject) bool {
return true
}
+// Verify returns true if the object exists in the content store and size is correct.
+func (s *ContentStore) Verify(meta *models.LFSMetaObject) (bool, error) {
+ path := filepath.Join(s.BasePath, transformKey(meta.Oid))
+
+ fi, err := os.Stat(path)
+ if os.IsNotExist(err) || err == nil && fi.Size() != meta.Size {
+ return false, nil
+ } else if err != nil {
+ return false, err
+ }
+
+ return true, nil
+}
+
func transformKey(key string) string {
if len(key) < 5 {
return key
diff --git a/modules/lfs/server.go b/modules/lfs/server.go
index d618d61853..68f2af1519 100644
--- a/modules/lfs/server.go
+++ b/modules/lfs/server.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
+ "path"
"regexp"
"strconv"
"strings"
@@ -15,6 +16,7 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
+
"github.com/dgrijalva/jwt-go"
"gopkg.in/macaron.v1"
)
@@ -66,7 +68,12 @@ type ObjectError struct {
// ObjectLink builds a URL linking to the object.
func (v *RequestVars) ObjectLink() string {
- return fmt.Sprintf("%s%s/%s/info/lfs/objects/%s", setting.AppURL, v.User, v.Repo, v.Oid)
+ return setting.AppURL + path.Join(v.User, v.Repo, "info/lfs/objects", v.Oid)
+}
+
+// VerifyLink builds a URL for verifying the object.
+func (v *RequestVars) VerifyLink() string {
+ return setting.AppURL + path.Join(v.User, v.Repo, "info/lfs/verify")
}
// link provides a structure used to build a hypermedia representation of an HTTP link.
@@ -320,6 +327,40 @@ func PutHandler(ctx *context.Context) {
logRequest(ctx.Req, 200)
}
+// VerifyHandler verify oid and its size from the content store
+func VerifyHandler(ctx *context.Context) {
+ if !setting.LFS.StartServer {
+ writeStatus(ctx, 404)
+ return
+ }
+
+ if !ContentMatcher(ctx.Req) {
+ writeStatus(ctx, 400)
+ return
+ }
+
+ rv := unpack(ctx)
+
+ meta, _ := getAuthenticatedRepoAndMeta(ctx, rv, true)
+ if meta == nil {
+ return
+ }
+
+ contentStore := &ContentStore{BasePath: setting.LFS.ContentPath}
+ ok, err := contentStore.Verify(meta)
+ if err != nil {
+ ctx.Resp.WriteHeader(500)
+ fmt.Fprintf(ctx.Resp, `{"message":"%s"}`, err)
+ return
+ }
+ if !ok {
+ writeStatus(ctx, 422)
+ return
+ }
+
+ logRequest(ctx.Req, 200)
+}
+
// Represent takes a RequestVars and Meta and turns it into a Representation suitable
// for json encoding
func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload bool) *Representation {
@@ -347,6 +388,11 @@ func Represent(rv *RequestVars, meta *models.LFSMetaObject, download, upload boo
rep.Actions["upload"] = &link{Href: rv.ObjectLink(), Header: header}
}
+ if upload && !download {
+ // Force client side verify action while gitea lacks proper server side verification
+ rep.Actions["verify"] = &link{Href: rv.VerifyLink(), Header: header}
+ }
+
return rep
}