mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Reject duplicate AccessToken names (#10994)
* make sure duplicate token names cannot be used * add check to api routes too * add @lunny s suggestion * fix & don't forget User.ID * AccessTokenByNameExists() return error too * unique token for each test * fix lint Signed-off-by: 6543 <6543@obermui.de> Co-authored-by: Lanre Adelowo <yo@lanre.wtf>
This commit is contained in:
		@@ -330,14 +330,18 @@ func loginUserWithPassword(t testing.TB, userName, password string) *TestSession
 | 
				
			|||||||
	return session
 | 
						return session
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//token has to be unique this counter take care of
 | 
				
			||||||
 | 
					var tokenCounter int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getTokenForLoggedInUser(t testing.TB, session *TestSession) string {
 | 
					func getTokenForLoggedInUser(t testing.TB, session *TestSession) string {
 | 
				
			||||||
	t.Helper()
 | 
						t.Helper()
 | 
				
			||||||
 | 
						tokenCounter++
 | 
				
			||||||
	req := NewRequest(t, "GET", "/user/settings/applications")
 | 
						req := NewRequest(t, "GET", "/user/settings/applications")
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	doc := NewHTMLParser(t, resp.Body)
 | 
						doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
	req = NewRequestWithValues(t, "POST", "/user/settings/applications", map[string]string{
 | 
						req = NewRequestWithValues(t, "POST", "/user/settings/applications", map[string]string{
 | 
				
			||||||
		"_csrf": doc.GetCSRF(),
 | 
							"_csrf": doc.GetCSRF(),
 | 
				
			||||||
		"name":  "api-testing-token",
 | 
							"name":  fmt.Sprintf("api-testing-token-%d", tokenCounter),
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusFound)
 | 
						resp = session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
	req = NewRequest(t, "GET", "/user/settings/applications")
 | 
						req = NewRequest(t, "GET", "/user/settings/applications")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,6 +77,11 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) {
 | 
				
			|||||||
	return nil, ErrAccessTokenNotExist{token}
 | 
						return nil, ErrAccessTokenNotExist{token}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// AccessTokenByNameExists checks if a token name has been used already by a user.
 | 
				
			||||||
 | 
					func AccessTokenByNameExists(token *AccessToken) (bool, error) {
 | 
				
			||||||
 | 
						return x.Table("access_token").Where("name = ?", token.Name).And("uid = ?", token.UID).Exist()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ListAccessTokens returns a list of access tokens belongs to given user.
 | 
					// ListAccessTokens returns a list of access tokens belongs to given user.
 | 
				
			||||||
func ListAccessTokens(uid int64, listOptions ListOptions) ([]*AccessToken, error) {
 | 
					func ListAccessTokens(uid int64, listOptions ListOptions) ([]*AccessToken, error) {
 | 
				
			||||||
	sess := x.
 | 
						sess := x.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,42 @@ func TestNewAccessToken(t *testing.T) {
 | 
				
			|||||||
	assert.Error(t, NewAccessToken(invalidToken))
 | 
						assert.Error(t, NewAccessToken(invalidToken))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestAccessTokenByNameExists(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						name := "Token Gitea"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
 | 
						token := &AccessToken{
 | 
				
			||||||
 | 
							UID:  3,
 | 
				
			||||||
 | 
							Name: name,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check to make sure it doesn't exists already
 | 
				
			||||||
 | 
						exist, err := AccessTokenByNameExists(token)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.False(t, exist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Save it to the database
 | 
				
			||||||
 | 
						assert.NoError(t, NewAccessToken(token))
 | 
				
			||||||
 | 
						AssertExistsAndLoadBean(t, token)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// This token must be found by name in the DB now
 | 
				
			||||||
 | 
						exist, err = AccessTokenByNameExists(token)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.True(t, exist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user4Token := &AccessToken{
 | 
				
			||||||
 | 
							UID:  4,
 | 
				
			||||||
 | 
							Name: name,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Name matches but different user ID, this shouldn't exists in the
 | 
				
			||||||
 | 
						// database
 | 
				
			||||||
 | 
						exist, err = AccessTokenByNameExists(user4Token)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.False(t, exist)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGetAccessTokenBySHA(t *testing.T) {
 | 
					func TestGetAccessTokenBySHA(t *testing.T) {
 | 
				
			||||||
	assert.NoError(t, PrepareTestDatabase())
 | 
						assert.NoError(t, PrepareTestDatabase())
 | 
				
			||||||
	token, err := GetAccessTokenBySHA("d2c6c1ba3890b309189a8e618c72a162e4efbf36")
 | 
						token, err := GetAccessTokenBySHA("d2c6c1ba3890b309189a8e618c72a162e4efbf36")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -517,6 +517,7 @@ new_token_desc = Applications using a token have full access to your account.
 | 
				
			|||||||
token_name = Token Name
 | 
					token_name = Token Name
 | 
				
			||||||
generate_token = Generate Token
 | 
					generate_token = Generate Token
 | 
				
			||||||
generate_token_success = Your new token has been generated. Copy it now as it will not be shown again.
 | 
					generate_token_success = Your new token has been generated. Copy it now as it will not be shown again.
 | 
				
			||||||
 | 
					generate_token_name_duplicate = <strong>%s</strong> has been used as an application name already. Please use a new one.
 | 
				
			||||||
delete_token = Delete
 | 
					delete_token = Delete
 | 
				
			||||||
access_token_deletion = Delete Access Token
 | 
					access_token_deletion = Delete Access Token
 | 
				
			||||||
access_token_deletion_desc = Deleting a token will revoke access to your account for applications using it. Continue?
 | 
					access_token_deletion_desc = Deleting a token will revoke access to your account for applications using it. Continue?
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@
 | 
				
			|||||||
package user
 | 
					package user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
@@ -89,6 +90,17 @@ func CreateAccessToken(ctx *context.APIContext, form api.CreateAccessTokenOption
 | 
				
			|||||||
		UID:  ctx.User.ID,
 | 
							UID:  ctx.User.ID,
 | 
				
			||||||
		Name: form.Name,
 | 
							Name: form.Name,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						exist, err := models.AccessTokenByNameExists(t)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.InternalServerError(err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if exist {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusBadRequest, "AccessTokenByNameExists", errors.New("access token name has been used already"))
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := models.NewAccessToken(t); err != nil {
 | 
						if err := models.NewAccessToken(t); err != nil {
 | 
				
			||||||
		ctx.Error(http.StatusInternalServerError, "NewAccessToken", err)
 | 
							ctx.Error(http.StatusInternalServerError, "NewAccessToken", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,18 @@ func ApplicationsPost(ctx *context.Context, form auth.NewAccessTokenForm) {
 | 
				
			|||||||
		UID:  ctx.User.ID,
 | 
							UID:  ctx.User.ID,
 | 
				
			||||||
		Name: form.Name,
 | 
							Name: form.Name,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						exist, err := models.AccessTokenByNameExists(t)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.ServerError("AccessTokenByNameExists", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if exist {
 | 
				
			||||||
 | 
							ctx.Flash.Error(ctx.Tr("settings.generate_token_name_duplicate", t.Name))
 | 
				
			||||||
 | 
							ctx.Redirect(setting.AppSubURL + "/user/settings/applications")
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := models.NewAccessToken(t); err != nil {
 | 
						if err := models.NewAccessToken(t); err != nil {
 | 
				
			||||||
		ctx.ServerError("NewAccessToken", err)
 | 
							ctx.ServerError("NewAccessToken", err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user