Skip to content

Git LFS support v2 #122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
Dec 26, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
74f1ff6
Import github.com/git-lfs/lfs-test-server as lfs module base
fabian-z Nov 6, 2016
f034682
Import github.com/dgrijalva/jwt-go into vendor/
fabian-z Nov 8, 2016
3d8fd95
Remove config, add JWT support from github.com/mgit-at/lfs-test-server
fabian-z Nov 6, 2016
7b3bfe8
Add LFS settings
fabian-z Nov 6, 2016
3727c21
Add LFS meta object model
fabian-z Nov 6, 2016
2e433b9
Add LFS routes and initialization
fabian-z Nov 6, 2016
9e8f91d
Adapt LFS module: handlers, routing, meta store
fabian-z Nov 6, 2016
f111811
Move LFS routes to /user/repo/info/lfs/*
Nov 7, 2016
c190661
Add request header checks to LFS BatchHandler / PostHandler
Nov 7, 2016
73c52ed
Implement LFS basic authentication
Nov 7, 2016
3b78c5b
Rework JWT secret generation / load
Nov 7, 2016
f7c78d9
Implement LFS SSH token authentication with JWT
fabian-z Nov 7, 2016
39a7b70
Integrate LFS settings into install process
fabian-z Nov 7, 2016
2568f71
Remove LFS objects when repository is deleted
Nov 8, 2016
307d1fd
Make LFS module stateless
Nov 8, 2016
f536978
Change 500 'Internal Server Error' to 400 'Bad Request'
Nov 9, 2016
f528c02
Change sql query to xorm call
fabian-z Nov 12, 2016
d769db2
Remove unneeded type from LFS module
fabian-z Nov 12, 2016
18a28f5
Change internal imports to code.gitea.io/gitea/
fabian-z Nov 12, 2016
5d5962b
Add Gitea authors copyright
fabian-z Nov 12, 2016
e2fe2e3
Change basic auth realm to "gitea-lfs"
fabian-z Nov 13, 2016
d27ee44
Add unique indexes to LFS model
fabian-z Nov 13, 2016
c024573
Use xorm count function in LFS check on repository delete
fabian-z Nov 13, 2016
4683c7d
Return io.ReadCloser from content store and close after usage
fabian-z Nov 13, 2016
71dae63
Add LFS info to runWeb()
fabian-z Nov 13, 2016
0daa396
Export LFS content store base path
Nov 14, 2016
9f10ad9
LFS file download from UI
fabian-z Nov 14, 2016
5c18b29
Work around git-lfs client issue with unauthenticated requests
fabian-z Nov 14, 2016
47691fa
Fix unauthenticated UI downloads from public repositories
fabian-z Nov 14, 2016
cb0f515
Authentication check order, Finish LFS file view logic
fabian-z Nov 14, 2016
6deed2d
Ignore LFS hooks if installed for current OS user
fabian-z Nov 17, 2016
728f52a
Hide LFS metafile diff from commit view, marking as binary
fabian-z Nov 20, 2016
d8a019d
Show LFS notice if file in commit view is tracked
fabian-z Nov 20, 2016
c8638c7
Add notbefore/nbf JWT claim
fabian-z Dec 25, 2016
3f4ed00
Correct lint suggestions - comments for structs and functions
fabian-z Dec 25, 2016
1817c86
Move secret generation code out of conditional
fabian-z Dec 25, 2016
6a38a8b
Do not hand out JWT tokens if LFS server support is disabled
fabian-z Dec 25, 2016
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
Prev Previous commit
Next Next commit
LFS file download from UI
  • Loading branch information
fabian-z committed Dec 25, 2016
commit 9f10ad9ad850a28127a1a868938295e812c7e114
1 change: 1 addition & 0 deletions cmd/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ func runWeb(ctx *cli.Context) error {
m.Group("/:reponame", func() {
m.Group("/info/lfs", func() {
m.Post("/objects/batch", lfs.BatchHandler)
m.Get("/objects/:oid/:filename", lfs.ObjectOidHandler)
m.Any("/objects/:oid", lfs.ObjectOidHandler)
m.Post("/objects", lfs.PostHandler)
}, ignSignInAndCsrf)
Expand Down
40 changes: 28 additions & 12 deletions modules/lfs/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func ObjectOidHandler(ctx *context.Context) {
GetMetaHandler(ctx)
return
}
if ContentMatcher(ctx.Req) {
if ContentMatcher(ctx.Req) || ctx.IsSigned {
GetContentHandler(ctx)
return
}
Expand Down Expand Up @@ -112,7 +112,7 @@ func GetContentHandler(ctx *context.Context) {
return
}

if !authenticate(repository, rv.Authorization, false) {
if !authenticate(ctx, repository, rv.Authorization, false) {
requireAuth(ctx)
return
}
Expand All @@ -137,6 +137,17 @@ func GetContentHandler(ctx *context.Context) {
return
}

ctx.Resp.Header().Set("Content-Length", strconv.FormatInt(meta.Size, 10))
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")

filename := ctx.Params("filename")
if len(filename) > 0 {
decodedFilename, err := base64.RawURLEncoding.DecodeString(filename)
if err == nil {
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename=\""+string(decodedFilename)+"\"")
}
}

ctx.Resp.WriteHeader(statusCode)
io.Copy(ctx.Resp, content)
content.Close()
Expand All @@ -161,7 +172,7 @@ func GetMetaHandler(ctx *context.Context) {
return
}

if !authenticate(repository, rv.Authorization, false) {
if !authenticate(ctx, repository, rv.Authorization, false) {
requireAuth(ctx)
return
}
Expand Down Expand Up @@ -200,7 +211,7 @@ func PostHandler(ctx *context.Context) {
return
}

if !authenticate(repository, rv.Authorization, true) {
if !authenticate(ctx, repository, rv.Authorization, true) {
requireAuth(ctx)
}

Expand Down Expand Up @@ -259,7 +270,7 @@ func BatchHandler(ctx *context.Context) {
requireWrite = true
}

if !authenticate(repository, object.Authorization, requireWrite) {
if !authenticate(ctx, repository, object.Authorization, requireWrite) {
requireAuth(ctx)
return
}
Expand Down Expand Up @@ -307,7 +318,7 @@ func PutHandler(ctx *context.Context) {
return
}

if !authenticate(repository, rv.Authorization, true) {
if !authenticate(ctx, repository, rv.Authorization, true) {
requireAuth(ctx)
return
}
Expand Down Expand Up @@ -428,7 +439,17 @@ func logRequest(r macaron.Request, status int) {

// authenticate uses the authorization string to determine whether
// or not to proceed. This server assumes an HTTP Basic auth format.
func authenticate(repository *models.Repository, authorization string, requireWrite bool) bool {
func authenticate(ctx *context.Context, repository *models.Repository, authorization string, requireWrite bool) bool {

accessMode := models.AccessModeRead
if requireWrite {
accessMode = models.AccessModeWrite
}

if ctx.IsSigned {
accessCheck, _ := models.HasAccess(ctx.User, repository, accessMode)
return accessCheck
}

if !repository.IsPrivate && !requireWrite {
return true
Expand Down Expand Up @@ -466,11 +487,6 @@ func authenticate(repository *models.Repository, authorization string, requireWr
return false
}

accessMode := models.AccessModeRead
if requireWrite {
accessMode = models.AccessModeWrite
}

accessCheck, _ := models.HasAccess(userModel, repository, accessMode)
return accessCheck
}
Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ file_view_raw = View Raw
file_permalink = Permalink
file_too_large = This file is too large to be shown
video_not_supported_in_browser = Your browser doesn't support HTML5 video tag.
stored_lfs = Stored with Git LFS

editor.new_file = New file
editor.upload_file = Upload file
Expand Down
26 changes: 26 additions & 0 deletions routers/repo/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ import (
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"encoding/base64"
"github.com/Unknwon/paginater"
"strconv"
)

const (
Expand Down Expand Up @@ -139,6 +142,29 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
isTextFile := base.IsTextFile(buf)
ctx.Data["IsTextFile"] = isTextFile

//Check for LFS meta file
if isTextFile {
headString := string(buf)
if strings.HasPrefix(headString, "version https://git-lfs.github.com/spec/v1") {
splitLines := strings.Split(headString, "\n")
if len(splitLines) >= 3 {
oid := strings.TrimPrefix(splitLines[1], "oid sha256:")
size, err := strconv.ParseInt(strings.TrimPrefix(splitLines[2], "size "), 10, 64)
if len(oid) == 64 && err == nil {
contentStore := &lfs.ContentStore{BasePath: setting.LFS.ContentPath}
meta := &models.LFSMetaObject{Oid: oid}
if contentStore.Exists(meta) {
ctx.Data["IsTextFile"] = false
ctx.Data["IsLFSFile"] = true
ctx.Data["FileSize"] = size
filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(blob.Name()))
ctx.Data["RawFileLink"] = fmt.Sprintf("%s%s/info/lfs/objects/%s/%s", setting.AppURL, ctx.Repo.Repository.FullName(), oid, filenameBase64)
}
}
}
}
}

// Assume file is not editable first.
if !isTextFile {
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.cannot_edit_non_text_files")
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/view_file.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
{{if .ReadmeInList}}
<strong>{{.FileName}}</strong>
{{else}}
<strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}</span>
<strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}</span>
{{end}}
{{else}}
<i class="file text outline icon ui left"></i>
<strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}</span>
<strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}</span>
{{end}}
{{if not .ReadmeInList}}
<div class="ui right file-actions">
Expand Down