* 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>master
@@ -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 | ||||