Skip to content

Commit

Permalink
api/v1: don't allow multiple tokens with same name
Browse files Browse the repository at this point in the history
Fail with 422 Unprocessable Entity if the token name
already exist

ref: gogs#5587
  • Loading branch information
frodeaa committed Oct 13, 2019
1 parent 1c82c42 commit 547d4a5
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 3 deletions.
13 changes: 13 additions & 0 deletions models/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,19 @@ func (err ErrAccessTokenNotExist) Error() string {
return fmt.Sprintf("access token does not exist [sha: %s]", err.SHA)
}

type ErrAccessTokenNameAlreadyExist struct {
Name string
}

func IsErrAccessTokenNameAlreadyExist(err error) bool {
_, ok := err.(ErrAccessTokenNameAlreadyExist)
return ok
}

func (err ErrAccessTokenNameAlreadyExist) Error() string {
return fmt.Sprintf("access token already exist [name: %s]", err.Name)
}

type ErrAccessTokenEmpty struct {
}

Expand Down
24 changes: 23 additions & 1 deletion models/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package models

import (
"fmt"
"time"

"github.com/go-xorm/xorm"
Expand Down Expand Up @@ -47,10 +48,25 @@ func (t *AccessToken) AfterSet(colName string, _ xorm.Cell) {
}
}

func isAccessTokenNameExist(uid int64, name string) (bool, error) {
tokens, err := ListAccessTokensByName(uid, name)
if err != nil {
return false, err
}
return len(tokens) > 0, nil
}

// NewAccessToken creates new access token.
func NewAccessToken(t *AccessToken) error {
t.Sha1 = tool.SHA1(gouuid.NewV4().String())
_, err := x.Insert(t)
has, err := isAccessTokenNameExist(t.UID, t.Name)
if err != nil {
return fmt.Errorf("IsAccessTokenNameExists: %v", err)
} else if has {
return ErrAccessTokenNameAlreadyExist{t.Name}
}

_, err = x.Insert(t)
return err
}

Expand All @@ -69,6 +85,12 @@ func GetAccessTokenBySHA(sha string) (*AccessToken, error) {
return t, nil
}

// ListAccessTokensByName returns a list of access tokens belongs to given user with name.
func ListAccessTokensByName(uid int64, name string) ([]*AccessToken, error) {
tokens := make([]*AccessToken, 0, 5)
return tokens, x.Where("uid=?", uid).And("name=?", name).Desc("id").Find(&tokens)
}

// ListAccessTokens returns a list of access tokens belongs to given user.
func ListAccessTokens(uid int64) ([]*AccessToken, error) {
tokens := make([]*AccessToken, 0, 5)
Expand Down
6 changes: 5 additions & 1 deletion routes/api/v1/user/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ func CreateAccessToken(c *context.APIContext, form api.CreateAccessTokenOption)
Name: form.Name,
}
if err := models.NewAccessToken(t); err != nil {
c.ServerError("NewAccessToken", err)
if models.IsErrAccessTokenNameAlreadyExist(err) {
c.Error(http.StatusUnprocessableEntity, "", err)
} else {
c.ServerError("NewAccessToken", err)
}
return
}
c.JSON(http.StatusCreated, &api.AccessToken{t.Name, t.Sha1})
Expand Down
7 changes: 6 additions & 1 deletion routes/user/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,12 @@ func SettingsApplicationsPost(c *context.Context, f form.NewAccessToken) {
Name: f.Name,
}
if err := models.NewAccessToken(t); err != nil {
c.ServerError("NewAccessToken", err)
if models.IsErrAccessTokenNameAlreadyExist(err) {
c.Flash.Error("NewAccessToken: " + err.Error())
c.SubURLRedirect("/user/settings/applications")
} else {
c.ServerError("NewAccessToken", err)
}
return
}

Expand Down

0 comments on commit 547d4a5

Please sign in to comment.