summaryrefslogtreecommitdiffstats
path: root/models/auth
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2022-08-25 10:31:57 +0800
committerGitHub <noreply@github.com>2022-08-25 10:31:57 +0800
commit1d8543e7db58d7c4973758e47f005c4d8bd7d7a3 (patch)
treeb60c99e2dfd69ccb998f8a0829d98d7cadcf0d6b /models/auth
parent4a4bfafa238bf48851f8c11fa3701bd42b912475 (diff)
downloadgitea-1d8543e7db58d7c4973758e47f005c4d8bd7d7a3.tar.gz
gitea-1d8543e7db58d7c4973758e47f005c4d8bd7d7a3.zip
Move some files into models' sub packages (#20262)
* Move some files into models' sub packages * Move functions * merge main branch * Fix check * fix check * Fix some tests * Fix lint * Fix lint * Revert lint changes * Fix error comments * Fix lint Co-authored-by: 6543 <6543@obermui.de>
Diffstat (limited to 'models/auth')
-rw-r--r--models/auth/main_test.go14
-rw-r--r--models/auth/oauth2_test.go69
-rw-r--r--models/auth/source_test.go11
-rw-r--r--models/auth/token.go230
-rw-r--r--models/auth/token_test.go132
-rw-r--r--models/auth/webauthn_test.go25
6 files changed, 422 insertions, 59 deletions
diff --git a/models/auth/main_test.go b/models/auth/main_test.go
index ccbdd4e81c..5d52e963b8 100644
--- a/models/auth/main_test.go
+++ b/models/auth/main_test.go
@@ -2,24 +2,22 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package auth
+package auth_test
import (
"path/filepath"
"testing"
"code.gitea.io/gitea/models/unittest"
+
+ _ "code.gitea.io/gitea/models"
+ _ "code.gitea.io/gitea/models/activities"
+ _ "code.gitea.io/gitea/models/auth"
+ _ "code.gitea.io/gitea/models/perm/access"
)
func TestMain(m *testing.M) {
unittest.MainTest(m, &unittest.TestOptions{
GiteaRootPath: filepath.Join("..", ".."),
- FixtureFiles: []string{
- "login_source.yml",
- "oauth2_application.yml",
- "oauth2_authorization_code.yml",
- "oauth2_grant.yml",
- "webauthn_credential.yml",
- },
})
}
diff --git a/models/auth/oauth2_test.go b/models/auth/oauth2_test.go
index 2a74f39998..3b2ba8c8f1 100644
--- a/models/auth/oauth2_test.go
+++ b/models/auth/oauth2_test.go
@@ -2,11 +2,12 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package auth
+package auth_test
import (
"testing"
+ auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
@@ -17,23 +18,23 @@ import (
func TestOAuth2Application_GenerateClientSecret(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1})
+ app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
secret, err := app.GenerateClientSecret()
assert.NoError(t, err)
assert.True(t, len(secret) > 0)
- unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1, ClientSecret: app.ClientSecret})
+ unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1, ClientSecret: app.ClientSecret})
}
func BenchmarkOAuth2Application_GenerateClientSecret(b *testing.B) {
assert.NoError(b, unittest.PrepareTestDatabase())
- app := unittest.AssertExistsAndLoadBean(b, &OAuth2Application{ID: 1})
+ app := unittest.AssertExistsAndLoadBean(b, &auth_model.OAuth2Application{ID: 1})
for i := 0; i < b.N; i++ {
_, _ = app.GenerateClientSecret()
}
}
func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
- app := &OAuth2Application{
+ app := &auth_model.OAuth2Application{
RedirectURIs: []string{"a", "b", "c"},
}
assert.True(t, app.ContainsRedirectURI("a"))
@@ -44,7 +45,7 @@ func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1})
+ app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
secret, err := app.GenerateClientSecret()
assert.NoError(t, err)
assert.True(t, app.ValidateClientSecret([]byte(secret)))
@@ -53,31 +54,31 @@ func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
func TestGetOAuth2ApplicationByClientID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- app, err := GetOAuth2ApplicationByClientID(db.DefaultContext, "da7da3ba-9a13-4167-856f-3899de0b0138")
+ app, err := auth_model.GetOAuth2ApplicationByClientID(db.DefaultContext, "da7da3ba-9a13-4167-856f-3899de0b0138")
assert.NoError(t, err)
assert.Equal(t, "da7da3ba-9a13-4167-856f-3899de0b0138", app.ClientID)
- app, err = GetOAuth2ApplicationByClientID(db.DefaultContext, "invalid client id")
+ app, err = auth_model.GetOAuth2ApplicationByClientID(db.DefaultContext, "invalid client id")
assert.Error(t, err)
assert.Nil(t, app)
}
func TestCreateOAuth2Application(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- app, err := CreateOAuth2Application(db.DefaultContext, CreateOAuth2ApplicationOptions{Name: "newapp", UserID: 1})
+ app, err := auth_model.CreateOAuth2Application(db.DefaultContext, auth_model.CreateOAuth2ApplicationOptions{Name: "newapp", UserID: 1})
assert.NoError(t, err)
assert.Equal(t, "newapp", app.Name)
assert.Len(t, app.ClientID, 36)
- unittest.AssertExistsAndLoadBean(t, &OAuth2Application{Name: "newapp"})
+ unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{Name: "newapp"})
}
func TestOAuth2Application_TableName(t *testing.T) {
- assert.Equal(t, "oauth2_application", new(OAuth2Application).TableName())
+ assert.Equal(t, "oauth2_application", new(auth_model.OAuth2Application).TableName())
}
func TestOAuth2Application_GetGrantByUserID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1})
+ app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
grant, err := app.GetGrantByUserID(db.DefaultContext, 1)
assert.NoError(t, err)
assert.Equal(t, int64(1), grant.UserID)
@@ -89,7 +90,7 @@ func TestOAuth2Application_GetGrantByUserID(t *testing.T) {
func TestOAuth2Application_CreateGrant(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1})
+ app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
grant, err := app.CreateGrant(db.DefaultContext, 2, "")
assert.NoError(t, err)
assert.NotNil(t, grant)
@@ -102,26 +103,26 @@ func TestOAuth2Application_CreateGrant(t *testing.T) {
func TestGetOAuth2GrantByID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- grant, err := GetOAuth2GrantByID(db.DefaultContext, 1)
+ grant, err := auth_model.GetOAuth2GrantByID(db.DefaultContext, 1)
assert.NoError(t, err)
assert.Equal(t, int64(1), grant.ID)
- grant, err = GetOAuth2GrantByID(db.DefaultContext, 34923458)
+ grant, err = auth_model.GetOAuth2GrantByID(db.DefaultContext, 34923458)
assert.NoError(t, err)
assert.Nil(t, grant)
}
func TestOAuth2Grant_IncreaseCounter(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Counter: 1})
+ grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 1})
assert.NoError(t, grant.IncreaseCounter(db.DefaultContext))
assert.Equal(t, int64(2), grant.Counter)
- unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Counter: 2})
+ unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Counter: 2})
}
func TestOAuth2Grant_ScopeContains(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Scope: "openid profile"})
+ grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1, Scope: "openid profile"})
assert.True(t, grant.ScopeContains("openid"))
assert.True(t, grant.ScopeContains("profile"))
assert.False(t, grant.ScopeContains("profil"))
@@ -130,7 +131,7 @@ func TestOAuth2Grant_ScopeContains(t *testing.T) {
func TestOAuth2Grant_GenerateNewAuthorizationCode(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1})
+ grant := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Grant{ID: 1})
code, err := grant.GenerateNewAuthorizationCode(db.DefaultContext, "https://example2.com/callback", "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg", "S256")
assert.NoError(t, err)
assert.NotNil(t, code)
@@ -138,46 +139,46 @@ func TestOAuth2Grant_GenerateNewAuthorizationCode(t *testing.T) {
}
func TestOAuth2Grant_TableName(t *testing.T) {
- assert.Equal(t, "oauth2_grant", new(OAuth2Grant).TableName())
+ assert.Equal(t, "oauth2_grant", new(auth_model.OAuth2Grant).TableName())
}
func TestGetOAuth2GrantsByUserID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- result, err := GetOAuth2GrantsByUserID(db.DefaultContext, 1)
+ result, err := auth_model.GetOAuth2GrantsByUserID(db.DefaultContext, 1)
assert.NoError(t, err)
assert.Len(t, result, 1)
assert.Equal(t, int64(1), result[0].ID)
assert.Equal(t, result[0].ApplicationID, result[0].Application.ID)
- result, err = GetOAuth2GrantsByUserID(db.DefaultContext, 34134)
+ result, err = auth_model.GetOAuth2GrantsByUserID(db.DefaultContext, 34134)
assert.NoError(t, err)
assert.Empty(t, result)
}
func TestRevokeOAuth2Grant(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- assert.NoError(t, RevokeOAuth2Grant(db.DefaultContext, 1, 1))
- unittest.AssertNotExistsBean(t, &OAuth2Grant{ID: 1, UserID: 1})
+ assert.NoError(t, auth_model.RevokeOAuth2Grant(db.DefaultContext, 1, 1))
+ unittest.AssertNotExistsBean(t, &auth_model.OAuth2Grant{ID: 1, UserID: 1})
}
//////////////////// Authorization Code
func TestGetOAuth2AuthorizationByCode(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- code, err := GetOAuth2AuthorizationByCode(db.DefaultContext, "authcode")
+ code, err := auth_model.GetOAuth2AuthorizationByCode(db.DefaultContext, "authcode")
assert.NoError(t, err)
assert.NotNil(t, code)
assert.Equal(t, "authcode", code.Code)
assert.Equal(t, int64(1), code.ID)
- code, err = GetOAuth2AuthorizationByCode(db.DefaultContext, "does not exist")
+ code, err = auth_model.GetOAuth2AuthorizationByCode(db.DefaultContext, "does not exist")
assert.NoError(t, err)
assert.Nil(t, code)
}
func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
// test plain
- code := &OAuth2AuthorizationCode{
+ code := &auth_model.OAuth2AuthorizationCode{
CodeChallengeMethod: "plain",
CodeChallenge: "test123",
}
@@ -185,7 +186,7 @@ func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
assert.False(t, code.ValidateCodeChallenge("ierwgjoergjio"))
// test S256
- code = &OAuth2AuthorizationCode{
+ code = &auth_model.OAuth2AuthorizationCode{
CodeChallengeMethod: "S256",
CodeChallenge: "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg",
}
@@ -193,14 +194,14 @@ func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
assert.False(t, code.ValidateCodeChallenge("wiogjerogorewngoenrgoiuenorg"))
// test unknown
- code = &OAuth2AuthorizationCode{
+ code = &auth_model.OAuth2AuthorizationCode{
CodeChallengeMethod: "monkey",
CodeChallenge: "foiwgjioriogeiogjerger",
}
assert.False(t, code.ValidateCodeChallenge("foiwgjioriogeiogjerger"))
// test no code challenge
- code = &OAuth2AuthorizationCode{
+ code = &auth_model.OAuth2AuthorizationCode{
CodeChallengeMethod: "",
CodeChallenge: "foierjiogerogerg",
}
@@ -208,7 +209,7 @@ func TestOAuth2AuthorizationCode_ValidateCodeChallenge(t *testing.T) {
}
func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) {
- code := &OAuth2AuthorizationCode{
+ code := &auth_model.OAuth2AuthorizationCode{
RedirectURI: "https://example.com/callback",
Code: "thecode",
}
@@ -224,11 +225,11 @@ func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) {
func TestOAuth2AuthorizationCode_Invalidate(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- code := unittest.AssertExistsAndLoadBean(t, &OAuth2AuthorizationCode{Code: "authcode"})
+ code := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"})
assert.NoError(t, code.Invalidate(db.DefaultContext))
- unittest.AssertNotExistsBean(t, &OAuth2AuthorizationCode{Code: "authcode"})
+ unittest.AssertNotExistsBean(t, &auth_model.OAuth2AuthorizationCode{Code: "authcode"})
}
func TestOAuth2AuthorizationCode_TableName(t *testing.T) {
- assert.Equal(t, "oauth2_authorization_code", new(OAuth2AuthorizationCode).TableName())
+ assert.Equal(t, "oauth2_authorization_code", new(auth_model.OAuth2AuthorizationCode).TableName())
}
diff --git a/models/auth/source_test.go b/models/auth/source_test.go
index 6a8e286910..67e96ee19e 100644
--- a/models/auth/source_test.go
+++ b/models/auth/source_test.go
@@ -2,12 +2,13 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package auth
+package auth_test
import (
"strings"
"testing"
+ auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/json"
@@ -37,13 +38,13 @@ func (source *TestSource) ToDB() ([]byte, error) {
func TestDumpAuthSource(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- authSourceSchema, err := db.TableInfo(new(Source))
+ authSourceSchema, err := db.TableInfo(new(auth_model.Source))
assert.NoError(t, err)
- RegisterTypeConfig(OAuth2, new(TestSource))
+ auth_model.RegisterTypeConfig(auth_model.OAuth2, new(TestSource))
- CreateSource(&Source{
- Type: OAuth2,
+ auth_model.CreateSource(&auth_model.Source{
+ Type: auth_model.OAuth2,
Name: "TestSource",
IsActive: false,
Cfg: &TestSource{
diff --git a/models/auth/token.go b/models/auth/token.go
new file mode 100644
index 0000000000..01654f2901
--- /dev/null
+++ b/models/auth/token.go
@@ -0,0 +1,230 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2019 The Gitea 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 auth
+
+import (
+ "crypto/subtle"
+ "fmt"
+ "time"
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
+
+ gouuid "github.com/google/uuid"
+ lru "github.com/hashicorp/golang-lru"
+)
+
+// ErrAccessTokenNotExist represents a "AccessTokenNotExist" kind of error.
+type ErrAccessTokenNotExist struct {
+ Token string
+}
+
+// IsErrAccessTokenNotExist checks if an error is a ErrAccessTokenNotExist.
+func IsErrAccessTokenNotExist(err error) bool {
+ _, ok := err.(ErrAccessTokenNotExist)
+ return ok
+}
+
+func (err ErrAccessTokenNotExist) Error() string {
+ return fmt.Sprintf("access token does not exist [sha: %s]", err.Token)
+}
+
+// ErrAccessTokenEmpty represents a "AccessTokenEmpty" kind of error.
+type ErrAccessTokenEmpty struct{}
+
+// IsErrAccessTokenEmpty checks if an error is a ErrAccessTokenEmpty.
+func IsErrAccessTokenEmpty(err error) bool {
+ _, ok := err.(ErrAccessTokenEmpty)
+ return ok
+}
+
+func (err ErrAccessTokenEmpty) Error() string {
+ return "access token is empty"
+}
+
+var successfulAccessTokenCache *lru.Cache
+
+// AccessToken represents a personal access token.
+type AccessToken struct {
+ ID int64 `xorm:"pk autoincr"`
+ UID int64 `xorm:"INDEX"`
+ Name string
+ Token string `xorm:"-"`
+ TokenHash string `xorm:"UNIQUE"` // sha256 of token
+ TokenSalt string
+ TokenLastEight string `xorm:"token_last_eight"`
+
+ CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
+ UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
+ HasRecentActivity bool `xorm:"-"`
+ HasUsed bool `xorm:"-"`
+}
+
+// AfterLoad is invoked from XORM after setting the values of all fields of this object.
+func (t *AccessToken) AfterLoad() {
+ t.HasUsed = t.UpdatedUnix > t.CreatedUnix
+ t.HasRecentActivity = t.UpdatedUnix.AddDuration(7*24*time.Hour) > timeutil.TimeStampNow()
+}
+
+func init() {
+ db.RegisterModel(new(AccessToken), func() error {
+ if setting.SuccessfulTokensCacheSize > 0 {
+ var err error
+ successfulAccessTokenCache, err = lru.New(setting.SuccessfulTokensCacheSize)
+ if err != nil {
+ return fmt.Errorf("unable to allocate AccessToken cache: %v", err)
+ }
+ } else {
+ successfulAccessTokenCache = nil
+ }
+ return nil
+ })
+}
+
+// NewAccessToken creates new access token.
+func NewAccessToken(t *AccessToken) error {
+ salt, err := util.CryptoRandomString(10)
+ if err != nil {
+ return err
+ }
+ t.TokenSalt = salt
+ t.Token = base.EncodeSha1(gouuid.New().String())
+ t.TokenHash = HashToken(t.Token, t.TokenSalt)
+ t.TokenLastEight = t.Token[len(t.Token)-8:]
+ _, err = db.GetEngine(db.DefaultContext).Insert(t)
+ return err
+}
+
+func getAccessTokenIDFromCache(token string) int64 {
+ if successfulAccessTokenCache == nil {
+ return 0
+ }
+ tInterface, ok := successfulAccessTokenCache.Get(token)
+ if !ok {
+ return 0
+ }
+ t, ok := tInterface.(int64)
+ if !ok {
+ return 0
+ }
+ return t
+}
+
+// GetAccessTokenBySHA returns access token by given token value
+func GetAccessTokenBySHA(token string) (*AccessToken, error) {
+ if token == "" {
+ return nil, ErrAccessTokenEmpty{}
+ }
+ // A token is defined as being SHA1 sum these are 40 hexadecimal bytes long
+ if len(token) != 40 {
+ return nil, ErrAccessTokenNotExist{token}
+ }
+ for _, x := range []byte(token) {
+ if x < '0' || (x > '9' && x < 'a') || x > 'f' {
+ return nil, ErrAccessTokenNotExist{token}
+ }
+ }
+
+ lastEight := token[len(token)-8:]
+
+ if id := getAccessTokenIDFromCache(token); id > 0 {
+ token := &AccessToken{
+ TokenLastEight: lastEight,
+ }
+ // Re-get the token from the db in case it has been deleted in the intervening period
+ has, err := db.GetEngine(db.DefaultContext).ID(id).Get(token)
+ if err != nil {
+ return nil, err
+ }
+ if has {
+ return token, nil
+ }
+ successfulAccessTokenCache.Remove(token)
+ }
+
+ var tokens []AccessToken
+ err := db.GetEngine(db.DefaultContext).Table(&AccessToken{}).Where("token_last_eight = ?", lastEight).Find(&tokens)
+ if err != nil {
+ return nil, err
+ } else if len(tokens) == 0 {
+ return nil, ErrAccessTokenNotExist{token}
+ }
+
+ for _, t := range tokens {
+ tempHash := HashToken(token, t.TokenSalt)
+ if subtle.ConstantTimeCompare([]byte(t.TokenHash), []byte(tempHash)) == 1 {
+ if successfulAccessTokenCache != nil {
+ successfulAccessTokenCache.Add(token, t.ID)
+ }
+ return &t, nil
+ }
+ }
+ return nil, ErrAccessTokenNotExist{token}
+}
+
+// AccessTokenByNameExists checks if a token name has been used already by a user.
+func AccessTokenByNameExists(token *AccessToken) (bool, error) {
+ return db.GetEngine(db.DefaultContext).Table("access_token").Where("name = ?", token.Name).And("uid = ?", token.UID).Exist()
+}
+
+// ListAccessTokensOptions contain filter options
+type ListAccessTokensOptions struct {
+ db.ListOptions
+ Name string
+ UserID int64
+}
+
+// ListAccessTokens returns a list of access tokens belongs to given user.
+func ListAccessTokens(opts ListAccessTokensOptions) ([]*AccessToken, error) {
+ sess := db.GetEngine(db.DefaultContext).Where("uid=?", opts.UserID)
+
+ if len(opts.Name) != 0 {
+ sess = sess.Where("name=?", opts.Name)
+ }
+
+ sess = sess.Desc("created_unix")
+
+ if opts.Page != 0 {
+ sess = db.SetSessionPagination(sess, &opts)
+
+ tokens := make([]*AccessToken, 0, opts.PageSize)
+ return tokens, sess.Find(&tokens)
+ }
+
+ tokens := make([]*AccessToken, 0, 5)
+ return tokens, sess.Find(&tokens)
+}
+
+// UpdateAccessToken updates information of access token.
+func UpdateAccessToken(t *AccessToken) error {
+ _, err := db.GetEngine(db.DefaultContext).ID(t.ID).AllCols().Update(t)
+ return err
+}
+
+// CountAccessTokens count access tokens belongs to given user by options
+func CountAccessTokens(opts ListAccessTokensOptions) (int64, error) {
+ sess := db.GetEngine(db.DefaultContext).Where("uid=?", opts.UserID)
+ if len(opts.Name) != 0 {
+ sess = sess.Where("name=?", opts.Name)
+ }
+ return sess.Count(&AccessToken{})
+}
+
+// DeleteAccessTokenByID deletes access token by given ID.
+func DeleteAccessTokenByID(id, userID int64) error {
+ cnt, err := db.GetEngine(db.DefaultContext).ID(id).Delete(&AccessToken{
+ UID: userID,
+ })
+ if err != nil {
+ return err
+ } else if cnt != 1 {
+ return ErrAccessTokenNotExist{}
+ }
+ return nil
+}
diff --git a/models/auth/token_test.go b/models/auth/token_test.go
new file mode 100644
index 0000000000..b27ff13406
--- /dev/null
+++ b/models/auth/token_test.go
@@ -0,0 +1,132 @@
+// Copyright 2016 The Gitea 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 auth_test
+
+import (
+ "testing"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ "code.gitea.io/gitea/models/unittest"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestNewAccessToken(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ token := &auth_model.AccessToken{
+ UID: 3,
+ Name: "Token C",
+ }
+ assert.NoError(t, auth_model.NewAccessToken(token))
+ unittest.AssertExistsAndLoadBean(t, token)
+
+ invalidToken := &auth_model.AccessToken{
+ ID: token.ID, // duplicate
+ UID: 2,
+ Name: "Token F",
+ }
+ assert.Error(t, auth_model.NewAccessToken(invalidToken))
+}
+
+func TestAccessTokenByNameExists(t *testing.T) {
+ name := "Token Gitea"
+
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ token := &auth_model.AccessToken{
+ UID: 3,
+ Name: name,
+ }
+
+ // Check to make sure it doesn't exists already
+ exist, err := auth_model.AccessTokenByNameExists(token)
+ assert.NoError(t, err)
+ assert.False(t, exist)
+
+ // Save it to the database
+ assert.NoError(t, auth_model.NewAccessToken(token))
+ unittest.AssertExistsAndLoadBean(t, token)
+
+ // This token must be found by name in the DB now
+ exist, err = auth_model.AccessTokenByNameExists(token)
+ assert.NoError(t, err)
+ assert.True(t, exist)
+
+ user4Token := &auth_model.AccessToken{
+ UID: 4,
+ Name: name,
+ }
+
+ // Name matches but different user ID, this shouldn't exists in the
+ // database
+ exist, err = auth_model.AccessTokenByNameExists(user4Token)
+ assert.NoError(t, err)
+ assert.False(t, exist)
+}
+
+func TestGetAccessTokenBySHA(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ token, err := auth_model.GetAccessTokenBySHA("d2c6c1ba3890b309189a8e618c72a162e4efbf36")
+ assert.NoError(t, err)
+ assert.Equal(t, int64(1), token.UID)
+ assert.Equal(t, "Token A", token.Name)
+ assert.Equal(t, "2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f", token.TokenHash)
+ assert.Equal(t, "e4efbf36", token.TokenLastEight)
+
+ _, err = auth_model.GetAccessTokenBySHA("notahash")
+ assert.Error(t, err)
+ assert.True(t, auth_model.IsErrAccessTokenNotExist(err))
+
+ _, err = auth_model.GetAccessTokenBySHA("")
+ assert.Error(t, err)
+ assert.True(t, auth_model.IsErrAccessTokenEmpty(err))
+}
+
+func TestListAccessTokens(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ tokens, err := auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 1})
+ assert.NoError(t, err)
+ if assert.Len(t, tokens, 2) {
+ assert.Equal(t, int64(1), tokens[0].UID)
+ assert.Equal(t, int64(1), tokens[1].UID)
+ assert.Contains(t, []string{tokens[0].Name, tokens[1].Name}, "Token A")
+ assert.Contains(t, []string{tokens[0].Name, tokens[1].Name}, "Token B")
+ }
+
+ tokens, err = auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 2})
+ assert.NoError(t, err)
+ if assert.Len(t, tokens, 1) {
+ assert.Equal(t, int64(2), tokens[0].UID)
+ assert.Equal(t, "Token A", tokens[0].Name)
+ }
+
+ tokens, err = auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 100})
+ assert.NoError(t, err)
+ assert.Empty(t, tokens)
+}
+
+func TestUpdateAccessToken(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ token, err := auth_model.GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c")
+ assert.NoError(t, err)
+ token.Name = "Token Z"
+
+ assert.NoError(t, auth_model.UpdateAccessToken(token))
+ unittest.AssertExistsAndLoadBean(t, token)
+}
+
+func TestDeleteAccessTokenByID(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+
+ token, err := auth_model.GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c")
+ assert.NoError(t, err)
+ assert.Equal(t, int64(1), token.UID)
+
+ assert.NoError(t, auth_model.DeleteAccessTokenByID(token.ID, 1))
+ unittest.AssertNotExistsBean(t, token)
+
+ err = auth_model.DeleteAccessTokenByID(100, 100)
+ assert.Error(t, err)
+ assert.True(t, auth_model.IsErrAccessTokenNotExist(err))
+}
diff --git a/models/auth/webauthn_test.go b/models/auth/webauthn_test.go
index edbb7ecd5b..29344376cc 100644
--- a/models/auth/webauthn_test.go
+++ b/models/auth/webauthn_test.go
@@ -2,11 +2,12 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package auth
+package auth_test
import (
"testing"
+ auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/unittest"
"github.com/duo-labs/webauthn/webauthn"
@@ -16,51 +17,51 @@ import (
func TestGetWebAuthnCredentialByID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- res, err := GetWebAuthnCredentialByID(1)
+ res, err := auth_model.GetWebAuthnCredentialByID(1)
assert.NoError(t, err)
assert.Equal(t, "WebAuthn credential", res.Name)
- _, err = GetWebAuthnCredentialByID(342432)
+ _, err = auth_model.GetWebAuthnCredentialByID(342432)
assert.Error(t, err)
- assert.True(t, IsErrWebAuthnCredentialNotExist(err))
+ assert.True(t, auth_model.IsErrWebAuthnCredentialNotExist(err))
}
func TestGetWebAuthnCredentialsByUID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- res, err := GetWebAuthnCredentialsByUID(32)
+ res, err := auth_model.GetWebAuthnCredentialsByUID(32)
assert.NoError(t, err)
assert.Len(t, res, 1)
assert.Equal(t, "WebAuthn credential", res[0].Name)
}
func TestWebAuthnCredential_TableName(t *testing.T) {
- assert.Equal(t, "webauthn_credential", WebAuthnCredential{}.TableName())
+ assert.Equal(t, "webauthn_credential", auth_model.WebAuthnCredential{}.TableName())
}
func TestWebAuthnCredential_UpdateSignCount(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- cred := unittest.AssertExistsAndLoadBean(t, &WebAuthnCredential{ID: 1})
+ cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1})
cred.SignCount = 1
assert.NoError(t, cred.UpdateSignCount())
- unittest.AssertExistsIf(t, true, &WebAuthnCredential{ID: 1, SignCount: 1})
+ unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1})
}
func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- cred := unittest.AssertExistsAndLoadBean(t, &WebAuthnCredential{ID: 1})
+ cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1})
cred.SignCount = 0xffffffff
assert.NoError(t, cred.UpdateSignCount())
- unittest.AssertExistsIf(t, true, &WebAuthnCredential{ID: 1, SignCount: 0xffffffff})
+ unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff})
}
func TestCreateCredential(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
- res, err := CreateCredential(1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")})
+ res, err := auth_model.CreateCredential(1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")})
assert.NoError(t, err)
assert.Equal(t, "WebAuthn Created Credential", res.Name)
assert.Equal(t, []byte("Test"), res.CredentialID)
- unittest.AssertExistsIf(t, true, &WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1})
+ unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{Name: "WebAuthn Created Credential", UserID: 1})
}