aboutsummaryrefslogtreecommitdiff
path: root/internal/db/access_tokens.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/db/access_tokens.go')
-rw-r--r--internal/db/access_tokens.go90
1 files changed, 90 insertions, 0 deletions
diff --git a/internal/db/access_tokens.go b/internal/db/access_tokens.go
index c3be93ac..f4f4ee80 100644
--- a/internal/db/access_tokens.go
+++ b/internal/db/access_tokens.go
@@ -6,27 +6,111 @@ package db
import (
"fmt"
+ "time"
"github.com/jinzhu/gorm"
+ gouuid "github.com/satori/go.uuid"
"gogs.io/gogs/internal/errutil"
+ "gogs.io/gogs/internal/tool"
)
// AccessTokensStore is the persistent interface for access tokens.
//
// NOTE: All methods are sorted in alphabetical order.
type AccessTokensStore interface {
+ // Create creates a new access token and persist to database.
+ // It returns ErrAccessTokenAlreadyExist when an access token
+ // with same name already exists for the user.
+ Create(userID int64, name string) (*AccessToken, error)
+ // DeleteByID deletes the access token by given ID.
+ // 🚨 SECURITY: The "userID" is required to prevent attacker
+ // deletes arbitrary access token that belongs to another user.
+ DeleteByID(userID, id int64) error
// GetBySHA returns the access token with given SHA1.
// It returns ErrAccessTokenNotExist when not found.
GetBySHA(sha string) (*AccessToken, error)
+ // List returns all access tokens belongs to given user.
+ List(userID int64) ([]*AccessToken, error)
// Save persists all values of given access token.
+ // The Updated field is set to current time automatically.
Save(t *AccessToken) error
}
var AccessTokens AccessTokensStore
+// AccessToken is a personal access token.
+type AccessToken struct {
+ ID int64
+ UserID int64 `xorm:"uid INDEX" gorm:"COLUMN:uid;INDEX"`
+ Name string
+ Sha1 string `xorm:"UNIQUE VARCHAR(40)" gorm:"TYPE:VARCHAR(40);UNIQUE"`
+
+ Created time.Time `xorm:"-" gorm:"-" json:"-"`
+ CreatedUnix int64
+ Updated time.Time `xorm:"-" gorm:"-" json:"-"`
+ UpdatedUnix int64
+ HasRecentActivity bool `xorm:"-" gorm:"-" json:"-"`
+ HasUsed bool `xorm:"-" gorm:"-" json:"-"`
+}
+
+// NOTE: This is a GORM create hook.
+func (t *AccessToken) BeforeCreate() {
+ t.CreatedUnix = t.Created.Unix()
+}
+
+// NOTE: This is a GORM update hook.
+func (t *AccessToken) BeforeUpdate() {
+ t.UpdatedUnix = t.Updated.Unix()
+}
+
+// NOTE: This is a GORM query hook.
+func (t *AccessToken) AfterFind() {
+ t.Created = time.Unix(t.CreatedUnix, 0).Local()
+ t.Updated = time.Unix(t.UpdatedUnix, 0).Local()
+ t.HasUsed = t.Updated.After(t.Created)
+ t.HasRecentActivity = t.Updated.Add(7 * 24 * time.Hour).After(time.Now())
+}
+
+var _ AccessTokensStore = (*accessTokens)(nil)
+
type accessTokens struct {
*gorm.DB
+ clock func() time.Time
+}
+
+type ErrAccessTokenAlreadyExist struct {
+ args errutil.Args
+}
+
+func IsErrAccessTokenAlreadyExist(err error) bool {
+ _, ok := err.(ErrAccessTokenAlreadyExist)
+ return ok
+}
+
+func (err ErrAccessTokenAlreadyExist) Error() string {
+ return fmt.Sprintf("access token already exists: %v", err.args)
+}
+
+func (db *accessTokens) Create(userID int64, name string) (*AccessToken, error) {
+ err := db.Where("uid = ? AND name = ?", userID, name).First(new(AccessToken)).Error
+ if err == nil {
+ return nil, ErrAccessTokenAlreadyExist{args: errutil.Args{"userID": userID, "name": name}}
+ } else if !gorm.IsRecordNotFoundError(err) {
+ return nil, err
+ }
+
+ token := &AccessToken{
+ UserID: userID,
+ Name: name,
+ Sha1: tool.SHA1(gouuid.NewV4().String()),
+ Created: db.clock(),
+ }
+ return token, db.DB.Create(token).Error
+}
+
+func (db *accessTokens) DeleteByID(userID, id int64) error {
+ return db.Where("id = ? AND uid = ?", id, userID).Delete(new(AccessToken)).Error
}
var _ errutil.NotFound = (*ErrAccessTokenNotExist)(nil)
@@ -60,6 +144,12 @@ func (db *accessTokens) GetBySHA(sha string) (*AccessToken, error) {
return token, nil
}
+func (db *accessTokens) List(userID int64) ([]*AccessToken, error) {
+ var tokens []*AccessToken
+ return tokens, db.Where("uid = ?", userID).Find(&tokens).Error
+}
+
func (db *accessTokens) Save(t *AccessToken) error {
+ t.Updated = db.clock()
return db.DB.Save(t).Error
}