diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2022-08-25 10:31:57 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-25 10:31:57 +0800 |
commit | 1d8543e7db58d7c4973758e47f005c4d8bd7d7a3 (patch) | |
tree | b60c99e2dfd69ccb998f8a0829d98d7cadcf0d6b /models/auth | |
parent | 4a4bfafa238bf48851f8c11fa3701bd42b912475 (diff) | |
download | gitea-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.go | 14 | ||||
-rw-r--r-- | models/auth/oauth2_test.go | 69 | ||||
-rw-r--r-- | models/auth/source_test.go | 11 | ||||
-rw-r--r-- | models/auth/token.go | 230 | ||||
-rw-r--r-- | models/auth/token_test.go | 132 | ||||
-rw-r--r-- | models/auth/webauthn_test.go | 25 |
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}) } |