aboutsummaryrefslogtreecommitdiff
path: root/internal/route
diff options
context:
space:
mode:
Diffstat (limited to 'internal/route')
-rw-r--r--internal/route/admin/auths.go38
-rw-r--r--internal/route/admin/users.go12
-rw-r--r--internal/route/api/v1/admin/user.go4
-rw-r--r--internal/route/api/v1/api.go2
-rw-r--r--internal/route/api/v1/repo/repo.go4
-rw-r--r--internal/route/api/v1/user/app.go4
-rw-r--r--internal/route/home.go2
-rw-r--r--internal/route/install.go13
-rw-r--r--internal/route/lfs/basic.go122
-rw-r--r--internal/route/lfs/batch.go182
-rw-r--r--internal/route/lfs/route.go159
-rw-r--r--internal/route/org/setting.go2
-rw-r--r--internal/route/org/teams.go6
-rw-r--r--internal/route/repo/http.go19
-rw-r--r--internal/route/repo/setting.go2
-rw-r--r--internal/route/user/auth.go10
-rw-r--r--internal/route/user/setting.go6
17 files changed, 522 insertions, 65 deletions
diff --git a/internal/route/admin/auths.go b/internal/route/admin/auths.go
index bcf52e5e..c5c1e480 100644
--- a/internal/route/admin/auths.go
+++ b/internal/route/admin/auths.go
@@ -32,7 +32,7 @@ func Authentications(c *context.Context) {
c.PageIs("AdminAuthentications")
var err error
- c.Data["Sources"], err = db.LoginSources()
+ c.Data["Sources"], err = db.ListLoginSources()
if err != nil {
c.Error(err, "list login sources")
return
@@ -49,11 +49,11 @@ type dropdownItem struct {
var (
authSources = []dropdownItem{
- {db.LoginNames[db.LOGIN_LDAP], db.LOGIN_LDAP},
- {db.LoginNames[db.LOGIN_DLDAP], db.LOGIN_DLDAP},
- {db.LoginNames[db.LOGIN_SMTP], db.LOGIN_SMTP},
- {db.LoginNames[db.LOGIN_PAM], db.LOGIN_PAM},
- {db.LoginNames[db.LOGIN_GITHUB], db.LOGIN_GITHUB},
+ {db.LoginNames[db.LoginLDAP], db.LoginLDAP},
+ {db.LoginNames[db.LoginDLDAP], db.LoginDLDAP},
+ {db.LoginNames[db.LoginSMTP], db.LoginSMTP},
+ {db.LoginNames[db.LoginPAM], db.LoginPAM},
+ {db.LoginNames[db.LoginGitHub], db.LoginGitHub},
}
securityProtocols = []dropdownItem{
{db.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_UNENCRYPTED], ldap.SECURITY_PROTOCOL_UNENCRYPTED},
@@ -67,8 +67,8 @@ func NewAuthSource(c *context.Context) {
c.PageIs("Admin")
c.PageIs("AdminAuthentications")
- c.Data["type"] = db.LOGIN_LDAP
- c.Data["CurrentTypeName"] = db.LoginNames[db.LOGIN_LDAP]
+ c.Data["type"] = db.LoginLDAP
+ c.Data["CurrentTypeName"] = db.LoginNames[db.LoginLDAP]
c.Data["CurrentSecurityProtocol"] = db.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_UNENCRYPTED]
c.Data["smtp_auth"] = "PLAIN"
c.Data["is_active"] = true
@@ -131,17 +131,17 @@ func NewAuthSourcePost(c *context.Context, f form.Authentication) {
hasTLS := false
var config core.Conversion
switch db.LoginType(f.Type) {
- case db.LOGIN_LDAP, db.LOGIN_DLDAP:
+ case db.LoginLDAP, db.LoginDLDAP:
config = parseLDAPConfig(f)
hasTLS = ldap.SecurityProtocol(f.SecurityProtocol) > ldap.SECURITY_PROTOCOL_UNENCRYPTED
- case db.LOGIN_SMTP:
+ case db.LoginSMTP:
config = parseSMTPConfig(f)
hasTLS = true
- case db.LOGIN_PAM:
+ case db.LoginPAM:
config = &db.PAMConfig{
ServiceName: f.PAMServiceName,
}
- case db.LOGIN_GITHUB:
+ case db.LoginGitHub:
config = &db.GitHubConfig{
APIEndpoint: strings.TrimSuffix(f.GitHubAPIEndpoint, "/") + "/",
}
@@ -186,7 +186,7 @@ func EditAuthSource(c *context.Context) {
c.Data["SecurityProtocols"] = securityProtocols
c.Data["SMTPAuths"] = db.SMTPAuths
- source, err := db.GetLoginSourceByID(c.ParamsInt64(":authid"))
+ source, err := db.LoginSources.GetByID(c.ParamsInt64(":authid"))
if err != nil {
c.Error(err, "get login source by ID")
return
@@ -204,7 +204,7 @@ func EditAuthSourcePost(c *context.Context, f form.Authentication) {
c.Data["SMTPAuths"] = db.SMTPAuths
- source, err := db.GetLoginSourceByID(c.ParamsInt64(":authid"))
+ source, err := db.LoginSources.GetByID(c.ParamsInt64(":authid"))
if err != nil {
c.Error(err, "get login source by ID")
return
@@ -219,15 +219,15 @@ func EditAuthSourcePost(c *context.Context, f form.Authentication) {
var config core.Conversion
switch db.LoginType(f.Type) {
- case db.LOGIN_LDAP, db.LOGIN_DLDAP:
+ case db.LoginLDAP, db.LoginDLDAP:
config = parseLDAPConfig(f)
- case db.LOGIN_SMTP:
+ case db.LoginSMTP:
config = parseSMTPConfig(f)
- case db.LOGIN_PAM:
+ case db.LoginPAM:
config = &db.PAMConfig{
ServiceName: f.PAMServiceName,
}
- case db.LOGIN_GITHUB:
+ case db.LoginGitHub:
config = &db.GitHubConfig{
APIEndpoint: strings.TrimSuffix(f.GitHubAPIEndpoint, "/") + "/",
}
@@ -252,7 +252,7 @@ func EditAuthSourcePost(c *context.Context, f form.Authentication) {
}
func DeleteAuthSource(c *context.Context) {
- source, err := db.GetLoginSourceByID(c.ParamsInt64(":authid"))
+ source, err := db.LoginSources.GetByID(c.ParamsInt64(":authid"))
if err != nil {
c.Error(err, "get login source by ID")
return
diff --git a/internal/route/admin/users.go b/internal/route/admin/users.go
index 630fa4ca..96257c59 100644
--- a/internal/route/admin/users.go
+++ b/internal/route/admin/users.go
@@ -32,7 +32,7 @@ func Users(c *context.Context) {
route.RenderUserSearch(c, &route.UserSearchOptions{
Type: db.USER_TYPE_INDIVIDUAL,
Counter: db.CountUsers,
- Ranger: db.Users,
+ Ranger: db.ListUsers,
PageSize: conf.UI.Admin.UserPagingNum,
OrderBy: "id ASC",
TplName: USERS,
@@ -46,7 +46,7 @@ func NewUser(c *context.Context) {
c.Data["login_type"] = "0-0"
- sources, err := db.LoginSources()
+ sources, err := db.ListLoginSources()
if err != nil {
c.Error(err, "list login sources")
return
@@ -62,7 +62,7 @@ func NewUserPost(c *context.Context, f form.AdminCrateUser) {
c.Data["PageIsAdmin"] = true
c.Data["PageIsAdminUsers"] = true
- sources, err := db.LoginSources()
+ sources, err := db.ListLoginSources()
if err != nil {
c.Error(err, "list login sources")
return
@@ -81,7 +81,7 @@ func NewUserPost(c *context.Context, f form.AdminCrateUser) {
Email: f.Email,
Passwd: f.Password,
IsActive: true,
- LoginType: db.LOGIN_PLAIN,
+ LoginType: db.LoginPlain,
}
if len(f.LoginType) > 0 {
@@ -132,7 +132,7 @@ func prepareUserInfo(c *context.Context) *db.User {
c.Data["User"] = u
if u.LoginSource > 0 {
- c.Data["LoginSource"], err = db.GetLoginSourceByID(u.LoginSource)
+ c.Data["LoginSource"], err = db.LoginSources.GetByID(u.LoginSource)
if err != nil {
c.Error(err, "get login source by ID")
return nil
@@ -141,7 +141,7 @@ func prepareUserInfo(c *context.Context) *db.User {
c.Data["LoginSource"] = &db.LoginSource{}
}
- sources, err := db.LoginSources()
+ sources, err := db.ListLoginSources()
if err != nil {
c.Error(err, "list login sources")
return nil
diff --git a/internal/route/api/v1/admin/user.go b/internal/route/api/v1/admin/user.go
index c339edd2..06c6569f 100644
--- a/internal/route/api/v1/admin/user.go
+++ b/internal/route/api/v1/admin/user.go
@@ -23,7 +23,7 @@ func parseLoginSource(c *context.APIContext, u *db.User, sourceID int64, loginNa
return
}
- source, err := db.GetLoginSourceByID(sourceID)
+ source, err := db.LoginSources.GetByID(sourceID)
if err != nil {
if errors.IsLoginSourceNotExist(err) {
c.ErrorStatus(http.StatusUnprocessableEntity, err)
@@ -45,7 +45,7 @@ func CreateUser(c *context.APIContext, form api.CreateUserOption) {
Email: form.Email,
Passwd: form.Password,
IsActive: true,
- LoginType: db.LOGIN_PLAIN,
+ LoginType: db.LoginPlain,
}
parseLoginSource(c, u, form.SourceID, form.LoginName)
diff --git a/internal/route/api/v1/api.go b/internal/route/api/v1/api.go
index 01f23d42..1ef21505 100644
--- a/internal/route/api/v1/api.go
+++ b/internal/route/api/v1/api.go
@@ -55,7 +55,7 @@ func repoAssignment() macaron.Handler {
}
if c.IsTokenAuth && c.User.IsAdmin {
- c.Repo.AccessMode = db.ACCESS_MODE_OWNER
+ c.Repo.AccessMode = db.AccessModeOwner
} else {
mode, err := db.UserAccessMode(c.UserID(), r)
if err != nil {
diff --git a/internal/route/api/v1/repo/repo.go b/internal/route/api/v1/repo/repo.go
index 71b94d75..8ac7fd87 100644
--- a/internal/route/api/v1/repo/repo.go
+++ b/internal/route/api/v1/repo/repo.go
@@ -131,8 +131,8 @@ func listUserRepositories(c *context.APIContext, username string) {
i := numOwnRepos
for repo, access := range accessibleRepos {
repos[i] = repo.APIFormat(&api.Permission{
- Admin: access >= db.ACCESS_MODE_ADMIN,
- Push: access >= db.ACCESS_MODE_WRITE,
+ Admin: access >= db.AccessModeAdmin,
+ Push: access >= db.AccessModeWrite,
Pull: true,
})
i++
diff --git a/internal/route/api/v1/user/app.go b/internal/route/api/v1/user/app.go
index 99a422cc..98532ae2 100644
--- a/internal/route/api/v1/user/app.go
+++ b/internal/route/api/v1/user/app.go
@@ -30,8 +30,8 @@ func ListAccessTokens(c *context.APIContext) {
func CreateAccessToken(c *context.APIContext, form api.CreateAccessTokenOption) {
t := &db.AccessToken{
- UID: c.User.ID,
- Name: form.Name,
+ UserID: c.User.ID,
+ Name: form.Name,
}
if err := db.NewAccessToken(t); err != nil {
if errors.IsAccessTokenNameAlreadyExist(err) {
diff --git a/internal/route/home.go b/internal/route/home.go
index 3da7f0cf..86a659d0 100644
--- a/internal/route/home.go
+++ b/internal/route/home.go
@@ -135,7 +135,7 @@ func ExploreUsers(c *context.Context) {
RenderUserSearch(c, &UserSearchOptions{
Type: db.USER_TYPE_INDIVIDUAL,
Counter: db.CountUsers,
- Ranger: db.Users,
+ Ranger: db.ListUsers,
PageSize: conf.UI.ExplorePagingNum,
OrderBy: "updated_unix DESC",
TplName: EXPLORE_USERS,
diff --git a/internal/route/install.go b/internal/route/install.go
index 899393b4..fbb605f0 100644
--- a/internal/route/install.go
+++ b/internal/route/install.go
@@ -86,9 +86,6 @@ func GlobalInit(customConf string) error {
db.InitDeliverHooks()
db.InitTestPullRequests()
}
- if db.EnableSQLite3 {
- log.Info("SQLite3 is supported")
- }
if conf.HasMinWinSvc {
log.Info("Builtin Windows Service is supported")
}
@@ -125,11 +122,7 @@ func InstallInit(c *context.Context) {
c.Title("install.install")
c.PageIs("Install")
- dbOpts := []string{"MySQL", "PostgreSQL", "MSSQL"}
- if db.EnableSQLite3 {
- dbOpts = append(dbOpts, "SQLite3")
- }
- c.Data["DbOptions"] = dbOpts
+ c.Data["DbOptions"] = []string{"MySQL", "PostgreSQL", "MSSQL", "SQLite3"}
}
func Install(c *context.Context) {
@@ -148,9 +141,7 @@ func Install(c *context.Context) {
case "mssql":
c.Data["CurDbOption"] = "MSSQL"
case "sqlite3":
- if db.EnableSQLite3 {
- c.Data["CurDbOption"] = "SQLite3"
- }
+ c.Data["CurDbOption"] = "SQLite3"
}
// Application general settings
diff --git a/internal/route/lfs/basic.go b/internal/route/lfs/basic.go
new file mode 100644
index 00000000..98597345
--- /dev/null
+++ b/internal/route/lfs/basic.go
@@ -0,0 +1,122 @@
+// Copyright 2020 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package lfs
+
+import (
+ "encoding/json"
+ "io"
+ "net/http"
+ "os"
+ "strconv"
+
+ log "unknwon.dev/clog/v2"
+
+ "gogs.io/gogs/internal/conf"
+ "gogs.io/gogs/internal/context"
+ "gogs.io/gogs/internal/db"
+ "gogs.io/gogs/internal/lfsutil"
+ "gogs.io/gogs/internal/strutil"
+)
+
+const transferBasic = "basic"
+const (
+ basicOperationUpload = "upload"
+ basicOperationDownload = "download"
+)
+
+// GET /{owner}/{repo}.git/info/lfs/object/basic/{oid}
+func serveBasicDownload(c *context.Context, repo *db.Repository, oid lfsutil.OID) {
+ object, err := db.LFS.GetObjectByOID(repo.ID, oid)
+ if err != nil {
+ if db.IsErrLFSObjectNotExist(err) {
+ responseJSON(c.Resp, http.StatusNotFound, responseError{
+ Message: "Object does not exist",
+ })
+ } else {
+ internalServerError(c.Resp)
+ log.Error("Failed to get object [repo_id: %d, oid: %s]: %v", repo.ID, oid, err)
+ }
+ return
+ }
+
+ fpath := lfsutil.StorageLocalPath(conf.LFS.ObjectsPath, object.OID)
+ r, err := os.Open(fpath)
+ if err != nil {
+ internalServerError(c.Resp)
+ log.Error("Failed to open object file [path: %s]: %v", fpath, err)
+ return
+ }
+ defer r.Close()
+
+ c.Header().Set("Content-Type", "application/octet-stream")
+ c.Header().Set("Content-Length", strconv.FormatInt(object.Size, 10))
+
+ _, err = io.Copy(c.Resp, r)
+ if err != nil {
+ c.Status(http.StatusInternalServerError)
+ log.Error("Failed to copy object file: %v", err)
+ return
+ }
+ c.Status(http.StatusOK)
+}
+
+// PUT /{owner}/{repo}.git/info/lfs/object/basic/{oid}
+func serveBasicUpload(c *context.Context, repo *db.Repository, oid lfsutil.OID) {
+ err := db.LFS.CreateObject(repo.ID, oid, c.Req.Request.Body, lfsutil.StorageLocal)
+ if err != nil {
+ internalServerError(c.Resp)
+ log.Error("Failed to create object [repo_id: %d, oid: %s]: %v", repo.ID, oid, err)
+ return
+ }
+ c.Status(http.StatusOK)
+
+ log.Trace("[LFS] Object created %q", oid)
+}
+
+// POST /{owner}/{repo}.git/info/lfs/object/basic/verify
+func serveBasicVerify(c *context.Context, repo *db.Repository) {
+ var request basicVerifyRequest
+ defer c.Req.Request.Body.Close()
+ err := json.NewDecoder(c.Req.Request.Body).Decode(&request)
+ if err != nil {
+ responseJSON(c.Resp, http.StatusBadRequest, responseError{
+ Message: strutil.ToUpperFirst(err.Error()),
+ })
+ return
+ }
+
+ if !lfsutil.ValidOID(request.Oid) {
+ responseJSON(c.Resp, http.StatusBadRequest, responseError{
+ Message: "Invalid oid",
+ })
+ return
+ }
+
+ object, err := db.LFS.GetObjectByOID(repo.ID, lfsutil.OID(request.Oid))
+ if err != nil {
+ if db.IsErrLFSObjectNotExist(err) {
+ responseJSON(c.Resp, http.StatusNotFound, responseError{
+ Message: "Object does not exist",
+ })
+ } else {
+ internalServerError(c.Resp)
+ log.Error("Failed to get object [repo_id: %d, oid: %s]: %v", repo.ID, request.Oid, err)
+ }
+ return
+ }
+
+ if object.Size != request.Size {
+ responseJSON(c.Resp, http.StatusNotFound, responseError{
+ Message: "Object size mismatch",
+ })
+ return
+ }
+ c.Status(http.StatusOK)
+}
+
+type basicVerifyRequest struct {
+ Oid lfsutil.OID `json:"oid"`
+ Size int64 `json:"size"`
+}
diff --git a/internal/route/lfs/batch.go b/internal/route/lfs/batch.go
new file mode 100644
index 00000000..ae53f5d3
--- /dev/null
+++ b/internal/route/lfs/batch.go
@@ -0,0 +1,182 @@
+// Copyright 2020 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package lfs
+
+import (
+ "fmt"
+ "net/http"
+
+ jsoniter "github.com/json-iterator/go"
+ log "unknwon.dev/clog/v2"
+
+ "gogs.io/gogs/internal/conf"
+ "gogs.io/gogs/internal/context"
+ "gogs.io/gogs/internal/db"
+ "gogs.io/gogs/internal/lfsutil"
+ "gogs.io/gogs/internal/strutil"
+)
+
+// POST /{owner}/{repo}.git/info/lfs/object/batch
+func serveBatch(c *context.Context, owner *db.User, repo *db.Repository) {
+ var request batchRequest
+ defer c.Req.Request.Body.Close()
+ err := jsoniter.NewDecoder(c.Req.Request.Body).Decode(&request)
+ if err != nil {
+ responseJSON(c.Resp, http.StatusBadRequest, responseError{
+ Message: strutil.ToUpperFirst(err.Error()),
+ })
+ return
+ }
+
+ // NOTE: We only support basic transfer as of now.
+ transfer := transferBasic
+ // Example: https://try.gogs.io/gogs/gogs.git/info/lfs/object/basic
+ baseHref := fmt.Sprintf("%s%s/%s.git/info/lfs/objects/basic", conf.Server.ExternalURL, owner.Name, repo.Name)
+
+ objects := make([]batchObject, 0, len(request.Objects))
+ switch request.Operation {
+ case basicOperationUpload:
+ for _, obj := range request.Objects {
+ var actions batchActions
+ if lfsutil.ValidOID(obj.Oid) {
+ actions = batchActions{
+ Upload: &batchAction{
+ Href: fmt.Sprintf("%s/%s", baseHref, obj.Oid),
+ },
+ Verify: &batchAction{
+ Href: fmt.Sprintf("%s/verify", baseHref),
+ },
+ }
+ } else {
+ actions = batchActions{
+ Error: &batchError{
+ Code: http.StatusUnprocessableEntity,
+ Message: "Object has invalid oid",
+ },
+ }
+ }
+
+ objects = append(objects, batchObject{
+ Oid: obj.Oid,
+ Size: obj.Size,
+ Actions: actions,
+ })
+ }
+
+ case basicOperationDownload:
+ oids := make([]lfsutil.OID, 0, len(request.Objects))
+ for _, obj := range request.Objects {
+ oids = append(oids, obj.Oid)
+ }
+ stored, err := db.LFS.GetObjectsByOIDs(repo.ID, oids...)
+ if err != nil {
+ internalServerError(c.Resp)
+ log.Error("Failed to get objects [repo_id: %d, oids: %v]: %v", repo.ID, oids, err)
+ return
+ }
+ storedSet := make(map[lfsutil.OID]*db.LFSObject, len(stored))
+ for _, obj := range stored {
+ storedSet[obj.OID] = obj
+ }
+
+ for _, obj := range request.Objects {
+ var actions batchActions
+ if stored := storedSet[obj.Oid]; stored != nil {
+ if stored.Size != obj.Size {
+ actions.Error = &batchError{
+ Code: http.StatusUnprocessableEntity,
+ Message: "Object size mismatch",
+ }
+ } else {
+ actions.Download = &batchAction{
+ Href: fmt.Sprintf("%s/%s", baseHref, obj.Oid),
+ }
+ }
+ } else {
+ actions.Error = &batchError{
+ Code: http.StatusNotFound,
+ Message: "Object does not exist",
+ }
+ }
+
+ objects = append(objects, batchObject{
+ Oid: obj.Oid,
+ Size: obj.Size,
+ Actions: actions,
+ })
+ }
+
+ default:
+ responseJSON(c.Resp, http.StatusBadRequest, responseError{
+ Message: "Operation not recognized",
+ })
+ return
+ }
+
+ responseJSON(c.Resp, http.StatusOK, batchResponse{
+ Transfer: transfer,
+ Objects: objects,
+ })
+}
+
+// batchRequest defines the request payload for the batch endpoint.
+type batchRequest struct {
+ Operation string `json:"operation"`
+ Objects []struct {
+ Oid lfsutil.OID `json:"oid"`
+ Size int64 `json:"size"`
+ } `json:"objects"`
+}
+
+type batchError struct {
+ Code int `json:"code"`
+ Message string `json:"message"`
+}
+
+type batchAction struct {
+ Href string `json:"href"`
+}
+
+type batchActions struct {
+ Download *batchAction `json:"download,omitempty"`
+ Upload *batchAction `json:"upload,omitempty"`
+ Verify *batchAction `json:"verify,omitempty"`
+ Error *batchError `json:"error,omitempty"`
+}
+
+type batchObject struct {
+ Oid lfsutil.OID `json:"oid"`
+ Size int64 `json:"size"`
+ Actions batchActions `json:"actions"`
+}
+
+// batchResponse defines the response payload for the batch endpoint.
+type batchResponse struct {
+ Transfer string `json:"transfer"`
+ Objects []batchObject `json:"objects"`
+}
+
+type responseError struct {
+ Message string `json:"message"`
+}
+
+const contentType = "application/vnd.git-lfs+json"
+
+func responseJSON(w http.ResponseWriter, status int, v interface{}) {
+ w.Header().Set("Content-Type", contentType)
+
+ err := jsoniter.NewEncoder(w).Encode(v)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ w.WriteHeader(status)
+}
+
+func internalServerError(w http.ResponseWriter) {
+ responseJSON(w, http.StatusInternalServerError, responseError{
+ Message: "Internal server error",
+ })
+}
diff --git a/internal/route/lfs/route.go b/internal/route/lfs/route.go
new file mode 100644
index 00000000..27224265
--- /dev/null
+++ b/internal/route/lfs/route.go
@@ -0,0 +1,159 @@
+// Copyright 2020 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package lfs
+
+import (
+ "net/http"
+ "strings"
+ "time"
+
+ "gopkg.in/macaron.v1"
+ log "unknwon.dev/clog/v2"
+
+ "gogs.io/gogs/internal/authutil"
+ "gogs.io/gogs/internal/context"
+ "gogs.io/gogs/internal/db"
+ "gogs.io/gogs/internal/lfsutil"
+)
+
+// RegisterRoutes registers LFS routes using given router, and inherits all groups and middleware.
+func RegisterRoutes(r *macaron.Router) {
+ verifyAccept := verifyHeader("Accept", contentType, http.StatusNotAcceptable)
+ verifyContentTypeJSON := verifyHeader("Content-Type", contentType, http.StatusBadRequest)
+ verifyContentTypeStream := verifyHeader("Content-Type", "application/octet-stream", http.StatusBadRequest)
+
+ r.Group("", func() {
+ r.Post("/objects/batch", authorize(db.AccessModeRead), verifyAccept, verifyContentTypeJSON, serveBatch)
+ r.Group("/objects/basic", func() {
+ r.Combo("/:oid", verifyOID()).
+ Get(authorize(db.AccessModeRead), serveBasicDownload).
+ Put(authorize(db.AccessModeWrite), verifyContentTypeStream, serveBasicUpload)
+ r.Post("/verify", authorize(db.AccessModeWrite), verifyAccept, verifyContentTypeJSON, serveBasicVerify)
+ })
+ }, authenticate())
+}
+
+// authenticate tries to authenticate user via HTTP Basic Auth.
+func authenticate() macaron.Handler {
+ askCredentials := func(w http.ResponseWriter) {
+ w.Header().Set("LFS-Authenticate", `Basic realm="Git LFS"`)
+ responseJSON(w, http.StatusUnauthorized, responseError{
+ Message: "Credentials needed",
+ })
+ }
+
+ return func(c *context.Context) {
+ username, password := authutil.DecodeBasic(c.Req.Header)
+ if username == "" {
+ askCredentials(c.Resp)
+ return
+ }
+
+ user, err := db.Users.Authenticate(username, password, -1)
+ if err != nil && !db.IsErrUserNotExist(err) {
+ c.Status(http.StatusInternalServerError)
+ log.Error("Failed to authenticate user [name: %s]: %v", username, err)
+ return
+ }
+
+ if err == nil && user.IsEnabledTwoFactor() {
+ c.PlainText(http.StatusBadRequest, `Users with 2FA enabled are not allowed to authenticate via username and password.`)
+ return
+ }
+
+ // If username and password authentication failed, try again using username as an access token.
+ if db.IsErrUserNotExist(err) {
+ token, err := db.AccessTokens.GetBySHA(username)
+ if err != nil {
+ if db.IsErrAccessTokenNotExist(err) {
+ askCredentials(c.Resp)
+ } else {
+ c.Status(http.StatusInternalServerError)
+ log.Error("Failed to get access token [sha: %s]: %v", username, err)
+ }
+ return
+ }
+ token.Updated = time.Now()
+ if err = db.AccessTokens.Save(token); err != nil {
+ log.Error("Failed to update access token: %v", err)
+ }
+
+ user, err = db.Users.GetByID(token.UserID)
+ if err != nil {
+ // Once we found the token, we're supposed to find its related user,
+ // thus any error is unexpected.
+ c.Status(http.StatusInternalServerError)
+ log.Error("Failed to get user: %v", err)
+ return
+ }
+ }
+
+ log.Trace("[LFS] Authenticated user: %s", user.Name)
+
+ c.Map(user)
+ }
+}
+
+// authorize tries to authorize the user to the context repository with given access mode.
+func authorize(mode db.AccessMode) macaron.Handler {
+ return func(c *context.Context, user *db.User) {
+ username := c.Params(":username")
+ reponame := strings.TrimSuffix(c.Params(":reponame"), ".git")
+
+ owner, err := db.Users.GetByUsername(username)
+ if err != nil {
+ if db.IsErrUserNotExist(err) {
+ c.Status(http.StatusNotFound)
+ } else {
+ c.Status(http.StatusInternalServerError)
+ log.Error("Failed to get user [name: %s]: %v", username, err)
+ }
+ return
+ }
+
+ repo, err := db.Repos.GetByName(owner.ID, reponame)
+ if err != nil {
+ if db.IsErrRepoNotExist(err) {
+ c.Status(http.StatusNotFound)
+ } else {
+ c.Status(http.StatusInternalServerError)
+ log.Error("Failed to get repository [owner_id: %d, name: %s]: %v", owner.ID, reponame, err)
+ }
+ return
+ }
+
+ if !db.Perms.Authorize(user.ID, repo, mode) {
+ c.Status(http.StatusNotFound)
+ return
+ }
+
+ c.Map(owner)
+ c.Map(repo)
+ }
+}
+
+// verifyHeader checks if the HTTP header value is matching.
+// When not, response given "failCode" as status code.
+func verifyHeader(key, value string, failCode int) macaron.Handler {
+ return func(c *context.Context) {
+ if c.Req.Header.Get(key) != value {
+ c.Status(failCode)
+ return
+ }
+ }
+}
+
+// verifyOID checks if the ":oid" URL parameter is valid.
+func verifyOID() macaron.Handler {
+ return func(c *context.Context) {
+ oid := lfsutil.OID(c.Params(":oid"))
+ if !lfsutil.ValidOID(oid) {
+ c.PlainText(http.StatusBadRequest, "Invalid oid")
+ return
+ }
+
+ c.Map(oid)
+ }
+}
diff --git a/internal/route/org/setting.go b/internal/route/org/setting.go
index 15b57623..64c30827 100644
--- a/internal/route/org/setting.go
+++ b/internal/route/org/setting.go
@@ -110,7 +110,7 @@ func SettingsDelete(c *context.Context) {
org := c.Org.Organization
if c.Req.Method == "POST" {
- if _, err := db.UserLogin(c.User.Name, c.Query("password"), c.User.LoginSource); err != nil {
+ if _, err := db.Users.Authenticate(c.User.Name, c.Query("password"), c.User.LoginSource); err != nil {
if db.IsErrUserNotExist(err) {
c.RenderWithErr(c.Tr("form.enterred_invalid_password"), SETTINGS_DELETE, nil)
} else {
diff --git a/internal/route/org/teams.go b/internal/route/org/teams.go
index a703a82d..6b0061fc 100644
--- a/internal/route/org/teams.go
+++ b/internal/route/org/teams.go
@@ -228,11 +228,11 @@ func EditTeamPost(c *context.Context, f form.CreateTeam) {
var auth db.AccessMode
switch f.Permission {
case "read":
- auth = db.ACCESS_MODE_READ
+ auth = db.AccessModeRead
case "write":
- auth = db.ACCESS_MODE_WRITE
+ auth = db.AccessModeWrite
case "admin":
- auth = db.ACCESS_MODE_ADMIN
+ auth = db.AccessModeAdmin
default:
c.Status(http.StatusUnauthorized)
return
diff --git a/internal/route/repo/http.go b/internal/route/repo/http.go
index 413b660f..c48cbdb8 100644
--- a/internal/route/repo/http.go
+++ b/internal/route/repo/http.go
@@ -12,6 +12,7 @@ import (
"os"
"os/exec"
"path"
+ "path/filepath"
"strconv"
"strings"
"time"
@@ -111,7 +112,7 @@ func HTTPContexter() macaron.Handler {
return
}
- authUser, err := db.UserLogin(authUsername, authPassword, -1)
+ authUser, err := db.Users.Authenticate(authUsername, authPassword, -1)
if err != nil && !db.IsErrUserNotExist(err) {
c.Error(err, "authenticate user")
return
@@ -119,9 +120,9 @@ func HTTPContexter() macaron.Handler {
// If username and password combination failed, try again using username as a token.
if authUser == nil {
- token, err := db.GetAccessTokenBySHA(authUsername)
+ token, err := db.AccessTokens.GetBySHA(authUsername)
if err != nil {
- if db.IsErrAccessTokenEmpty(err) || db.IsErrAccessTokenNotExist(err) {
+ if db.IsErrAccessTokenNotExist(err) {
askCredentials(c, http.StatusUnauthorized, "")
} else {
c.Error(err, "get access token by SHA")
@@ -129,9 +130,11 @@ func HTTPContexter() macaron.Handler {
return
}
token.Updated = time.Now()
- // TODO: verify or update token.Updated in database
+ if err = db.AccessTokens.Save(token); err != nil {
+ log.Error("Failed to update access token: %v", err)
+ }
- authUser, err = db.GetUserByID(token.UID)
+ authUser, err = db.GetUserByID(token.UserID)
if err != nil {
// Once we found token, we're supposed to find its related user,
// thus any error is unexpected.
@@ -146,9 +149,9 @@ Please create and use personal access token on user settings page`)
log.Trace("HTTPGit - Authenticated user: %s", authUser.Name)
- mode := db.ACCESS_MODE_WRITE
+ mode := db.AccessModeWrite
if isPull {
- mode = db.ACCESS_MODE_READ
+ mode = db.AccessModeRead
}
has, err := db.HasAccess(authUser.ID, repo, mode)
if err != nil {
@@ -367,7 +370,7 @@ func getGitRepoPath(dir string) (string, error) {
dir += ".git"
}
- filename := path.Join(conf.Repository.Root, dir)
+ filename := filepath.Join(conf.Repository.Root, dir)
if _, err := os.Stat(filename); os.IsNotExist(err) {
return "", err
}
diff --git a/internal/route/repo/setting.go b/internal/route/repo/setting.go
index 1c4446d0..fd281dcc 100644
--- a/internal/route/repo/setting.go
+++ b/internal/route/repo/setting.go
@@ -513,7 +513,7 @@ func SettingsProtectedBranch(c *context.Context) {
c.Data["Users"] = users
c.Data["whitelist_users"] = protectBranch.WhitelistUserIDs
- teams, err := c.Repo.Owner.TeamsHaveAccessToRepo(c.Repo.Repository.ID, db.ACCESS_MODE_WRITE)
+ teams, err := c.Repo.Owner.TeamsHaveAccessToRepo(c.Repo.Repository.ID, db.AccessModeWrite)
if err != nil {
c.Error(err, "get teams have access to the repository")
return
diff --git a/internal/route/user/auth.go b/internal/route/user/auth.go
index a29b6311..22e8176c 100644
--- a/internal/route/user/auth.go
+++ b/internal/route/user/auth.go
@@ -9,12 +9,12 @@ import (
"net/url"
"github.com/go-macaron/captcha"
+ "github.com/pkg/errors"
log "unknwon.dev/clog/v2"
"gogs.io/gogs/internal/conf"
"gogs.io/gogs/internal/context"
"gogs.io/gogs/internal/db"
- "gogs.io/gogs/internal/db/errors"
"gogs.io/gogs/internal/email"
"gogs.io/gogs/internal/form"
"gogs.io/gogs/internal/tool"
@@ -160,13 +160,13 @@ func LoginPost(c *context.Context, f form.SignIn) {
return
}
- u, err := db.UserLogin(f.UserName, f.Password, f.LoginSource)
+ u, err := db.Users.Authenticate(f.UserName, f.Password, f.LoginSource)
if err != nil {
- switch err.(type) {
+ switch errors.Cause(err).(type) {
case db.ErrUserNotExist:
c.FormErr("UserName", "Password")
c.RenderWithErr(c.Tr("form.username_password_incorrect"), LOGIN, &f)
- case errors.LoginSourceMismatch:
+ case db.ErrLoginSourceMismatch:
c.FormErr("LoginSource")
c.RenderWithErr(c.Tr("form.auth_source_mismatch"), LOGIN, &f)
@@ -263,7 +263,7 @@ func LoginTwoFactorRecoveryCodePost(c *context.Context) {
}
if err := db.UseRecoveryCode(userID, c.Query("recovery_code")); err != nil {
- if errors.IsTwoFactorRecoveryCodeNotFound(err) {
+ if db.IsTwoFactorRecoveryCodeNotFound(err) {
c.Flash.Error(c.Tr("auth.login_two_factor_invalid_recovery_code"))
c.RedirectSubpath("/user/login/two_factor_recovery_code")
} else {
diff --git a/internal/route/user/setting.go b/internal/route/user/setting.go
index c9ccdc8f..63575c9e 100644
--- a/internal/route/user/setting.go
+++ b/internal/route/user/setting.go
@@ -608,8 +608,8 @@ func SettingsApplicationsPost(c *context.Context, f form.NewAccessToken) {
}
t := &db.AccessToken{
- UID: c.User.ID,
- Name: f.Name,
+ UserID: c.User.ID,
+ Name: f.Name,
}
if err := db.NewAccessToken(t); err != nil {
if errors.IsAccessTokenNameAlreadyExist(err) {
@@ -643,7 +643,7 @@ func SettingsDelete(c *context.Context) {
c.PageIs("SettingsDelete")
if c.Req.Method == "POST" {
- if _, err := db.UserLogin(c.User.Name, c.Query("password"), c.User.LoginSource); err != nil {
+ if _, err := db.Users.Authenticate(c.User.Name, c.Query("password"), c.User.LoginSource); err != nil {
if db.IsErrUserNotExist(err) {
c.RenderWithErr(c.Tr("form.enterred_invalid_password"), SETTINGS_DELETE, nil)
} else {