Hash App token (#6724)
This commit is contained in:
		
							parent
							
								
									1fa9662946
								
							
						
					
					
						commit
						46373e7657
					
				
					 16 changed files with 239 additions and 44 deletions
				
			
		
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							|  | @ -3,7 +3,7 @@ module code.gitea.io/gitea | |||
| go 1.12 | ||||
| 
 | ||||
| require ( | ||||
| 	code.gitea.io/sdk v0.0.0-20190416172854-7d954d775498 | ||||
| 	code.gitea.io/sdk v0.0.0-20190419065346-2858b80da5f7 | ||||
| 	github.com/BurntSushi/toml v0.3.1 // indirect | ||||
| 	github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 | ||||
| 	github.com/RoaringBitmap/roaring v0.4.7 // indirect | ||||
|  |  | |||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							|  | @ -1,6 +1,6 @@ | |||
| cloud.google.com/go v0.30.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||||
| code.gitea.io/sdk v0.0.0-20190416172854-7d954d775498 h1:rcjwXMYIjYts88akPiyy/GB+imecpf159jojChciEEw= | ||||
| code.gitea.io/sdk v0.0.0-20190416172854-7d954d775498/go.mod h1:5bZt0dRznpn2JysytQnV0yCru3FwDv9O5G91jo+lDAk= | ||||
| code.gitea.io/sdk v0.0.0-20190419065346-2858b80da5f7 h1:YggbbCVgggcOjKYmcB2wVOsEtJHgHUNFFJZDB6QcYTg= | ||||
| code.gitea.io/sdk v0.0.0-20190419065346-2858b80da5f7/go.mod h1:5bZt0dRznpn2JysytQnV0yCru3FwDv9O5G91jo+lDAk= | ||||
| github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | ||||
| github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||||
| github.com/PuerkitoBio/goquery v0.0.0-20170324135448-ed7d758e9a34 h1:UsHpWO0Elp6NaWVARdZHjiYwkhrspHVEGsyIKPb9OI8= | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ func TestAPICreateAndDeleteToken(t *testing.T) { | |||
| 	models.AssertExistsAndLoadBean(t, &models.AccessToken{ | ||||
| 		ID:    newAccessToken.ID, | ||||
| 		Name:  newAccessToken.Name, | ||||
| 		Sha1: newAccessToken.Sha1, | ||||
| 		Token: newAccessToken.Token, | ||||
| 		UID:   user.ID, | ||||
| 	}) | ||||
| 
 | ||||
|  |  | |||
|  | @ -507,7 +507,7 @@ func (err ErrDeployKeyNameAlreadyUsed) Error() string { | |||
| 
 | ||||
| // ErrAccessTokenNotExist represents a "AccessTokenNotExist" kind of error.
 | ||||
| type ErrAccessTokenNotExist struct { | ||||
| 	SHA string | ||||
| 	Token string | ||||
| } | ||||
| 
 | ||||
| // IsErrAccessTokenNotExist checks if an error is a ErrAccessTokenNotExist.
 | ||||
|  | @ -517,7 +517,7 @@ func IsErrAccessTokenNotExist(err error) bool { | |||
| } | ||||
| 
 | ||||
| func (err ErrAccessTokenNotExist) Error() string { | ||||
| 	return fmt.Sprintf("access token does not exist [sha: %s]", err.SHA) | ||||
| 	return fmt.Sprintf("access token does not exist [sha: %s]", err.Token) | ||||
| } | ||||
| 
 | ||||
| // ErrAccessTokenEmpty represents a "AccessTokenEmpty" kind of error.
 | ||||
|  |  | |||
|  | @ -2,7 +2,10 @@ | |||
|   id: 1 | ||||
|   uid: 1 | ||||
|   name: Token A | ||||
|   sha1: hash1 | ||||
|   #token: d2c6c1ba3890b309189a8e618c72a162e4efbf36 | ||||
|   token_hash: 2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f | ||||
|   token_salt: QuSiZr1byZ | ||||
|   token_last_eight: e4efbf36 | ||||
|   created_unix: 946687980 | ||||
|   updated_unix: 946687980 | ||||
| 
 | ||||
|  | @ -10,7 +13,10 @@ | |||
|   id: 2 | ||||
|   uid: 1 | ||||
|   name: Token B | ||||
|   sha1: hash2 | ||||
|   #token: 4c6f36e6cf498e2a448662f915d932c09c5a146c | ||||
|   token_hash: 1a0e32a231ebbd582dc626c1543a42d3c63d4fa76c07c72862721467c55e8f81c923d60700f0528b5f5f443f055559d3a279 | ||||
|   token_salt: Lfwopukrq5 | ||||
|   token_last_eight: 9c5a146c | ||||
|   created_unix: 946687980 | ||||
|   updated_unix: 946687980 | ||||
| 
 | ||||
|  | @ -18,6 +24,10 @@ | |||
|   id: 3 | ||||
|   uid: 2 | ||||
|   name: Token A | ||||
|   sha1: hash3 | ||||
|   #token: 90a18faa671dc43924b795806ffe4fd169d28c91 | ||||
|   token_hash: d6d404048048812d9e911d93aefbe94fc768d4876fdf75e3bef0bdc67828e0af422846d3056f2f25ec35c51dc92075685ec5 | ||||
|   token_salt: 99ArgXKlQQ | ||||
|   token_last_eight: 69d28c91 | ||||
|   created_unix: 946687980 | ||||
|   updated_unix: 946687980 | ||||
| #commented out tokens so you can see what they are in plaintext | ||||
|  | @ -223,6 +223,8 @@ var migrations = []Migration{ | |||
| 	NewMigration("add uploader id for table attachment", addUploaderIDForAttachment), | ||||
| 	// v84 -> v85
 | ||||
| 	NewMigration("add table to store original imported gpg keys", addGPGKeyImport), | ||||
| 	// v85 -> v86
 | ||||
| 	NewMigration("hash application token", hashAppToken), | ||||
| } | ||||
| 
 | ||||
| // Migrate database to current version
 | ||||
|  |  | |||
							
								
								
									
										135
									
								
								models/migrations/v85.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								models/migrations/v85.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,135 @@ | |||
| // 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 migrations | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"github.com/go-xorm/core" | ||||
| 	"github.com/go-xorm/xorm" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/models" | ||||
| 	"code.gitea.io/gitea/modules/generate" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
| ) | ||||
| 
 | ||||
| func hashAppToken(x *xorm.Engine) error { | ||||
| 	// AccessToken see models/token.go
 | ||||
| 	type AccessToken struct { | ||||
| 		ID             int64 `xorm:"pk autoincr"` | ||||
| 		UID            int64 `xorm:"INDEX"` | ||||
| 		Name           string | ||||
| 		Sha1           string | ||||
| 		Token          string `xorm:"-"` | ||||
| 		TokenHash      string `xorm:"UNIQUE"` // sha256 of token
 | ||||
| 		TokenSalt      string | ||||
| 		TokenLastEight string `xorm:"token_last_eight"` | ||||
| 
 | ||||
| 		CreatedUnix       util.TimeStamp `xorm:"INDEX created"` | ||||
| 		UpdatedUnix       util.TimeStamp `xorm:"INDEX updated"` | ||||
| 		HasRecentActivity bool           `xorm:"-"` | ||||
| 		HasUsed           bool           `xorm:"-"` | ||||
| 	} | ||||
| 
 | ||||
| 	// First remove the index
 | ||||
| 	sess := x.NewSession() | ||||
| 	defer sess.Close() | ||||
| 	if err := sess.Begin(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	var err error | ||||
| 	if models.DbCfg.Type == core.POSTGRES || models.DbCfg.Type == core.SQLITE { | ||||
| 		_, err = sess.Exec("DROP INDEX IF EXISTS UQE_access_token_sha1") | ||||
| 	} else if models.DbCfg.Type == core.MSSQL { | ||||
| 		_, err = sess.Exec(`DECLARE @ConstraintName VARCHAR(256) | ||||
| 		DECLARE @SQL NVARCHAR(256) | ||||
| 		SELECT @ConstraintName = obj.name FROM sys.columns col LEFT OUTER JOIN sys.objects obj ON obj.object_id = col.default_object_id AND obj.type = 'D' WHERE col.object_id = OBJECT_ID('access_token') AND obj.name IS NOT NULL AND col.name = 'sha1' | ||||
| 		SET @SQL = N'ALTER TABLE [access_token] DROP CONSTRAINT [' + @ConstraintName + N']' | ||||
| 		EXEC sp_executesql @SQL`) | ||||
| 	} else if models.DbCfg.Type == core.MYSQL { | ||||
| 		indexes, err := sess.QueryString(`SHOW INDEX FROM access_token WHERE KEY_NAME = 'UQE_access_token_sha1'`) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		if len(indexes) >= 1 { | ||||
| 			_, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token") | ||||
| 		} | ||||
| 	} else { | ||||
| 		_, err = sess.Exec("DROP INDEX UQE_access_token_sha1 ON access_token") | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("Drop index failed: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err = sess.Commit(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := sess.Begin(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := x.Sync2(new(AccessToken)); err != nil { | ||||
| 		return fmt.Errorf("Sync2: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if err = sess.Commit(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := sess.Begin(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	// transform all tokens to hashes
 | ||||
| 	const batchSize = 100 | ||||
| 	for start := 0; ; start += batchSize { | ||||
| 		tokens := make([]*AccessToken, 0, batchSize) | ||||
| 		if err := sess.Limit(batchSize, start).Find(&tokens); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if len(tokens) == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		for _, token := range tokens { | ||||
| 			// generate salt
 | ||||
| 			salt, err := generate.GetRandomString(10) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			token.TokenSalt = salt | ||||
| 			token.TokenHash = hashToken(token.Sha1, salt) | ||||
| 			if len(token.Sha1) < 8 { | ||||
| 				log.Warn("Unable to transform token %s with name %s belonging to user ID %d, skipping transformation", token.Sha1, token.Name, token.UID) | ||||
| 				continue | ||||
| 			} | ||||
| 			token.TokenLastEight = token.Sha1[len(token.Sha1)-8:] | ||||
| 			token.Sha1 = "" // ensure to blank out column in case drop column doesn't work
 | ||||
| 
 | ||||
| 			if _, err := sess.ID(token.ID).Cols("token_hash, token_salt, token_last_eight, sha1").Update(token); err != nil { | ||||
| 				return fmt.Errorf("couldn't add in sha1, token_hash, token_salt and token_last_eight: %v", err) | ||||
| 			} | ||||
| 
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Commit and begin new transaction for dropping columns
 | ||||
| 	if err := sess.Commit(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := sess.Begin(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := dropTableColumns(sess, "access_token", "sha1"); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sess.Commit() | ||||
| 
 | ||||
| } | ||||
|  | @ -1,15 +1,18 @@ | |||
| // 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 models | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/subtle" | ||||
| 	"time" | ||||
| 
 | ||||
| 	gouuid "github.com/satori/go.uuid" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/modules/base" | ||||
| 	"code.gitea.io/gitea/modules/generate" | ||||
| 	"code.gitea.io/gitea/modules/util" | ||||
| ) | ||||
| 
 | ||||
|  | @ -18,7 +21,10 @@ type AccessToken struct { | |||
| 	ID             int64 `xorm:"pk autoincr"` | ||||
| 	UID            int64 `xorm:"INDEX"` | ||||
| 	Name           string | ||||
| 	Sha1 string `xorm:"UNIQUE VARCHAR(40)"` | ||||
| 	Token          string `xorm:"-"` | ||||
| 	TokenHash      string `xorm:"UNIQUE"` // sha256 of token
 | ||||
| 	TokenSalt      string | ||||
| 	TokenLastEight string `xorm:"token_last_eight"` | ||||
| 
 | ||||
| 	CreatedUnix       util.TimeStamp `xorm:"INDEX created"` | ||||
| 	UpdatedUnix       util.TimeStamp `xorm:"INDEX updated"` | ||||
|  | @ -34,24 +40,41 @@ func (t *AccessToken) AfterLoad() { | |||
| 
 | ||||
| // NewAccessToken creates new access token.
 | ||||
| func NewAccessToken(t *AccessToken) error { | ||||
| 	t.Sha1 = base.EncodeSha1(gouuid.NewV4().String()) | ||||
| 	_, err := x.Insert(t) | ||||
| 	salt, err := generate.GetRandomString(10) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	t.TokenSalt = salt | ||||
| 	t.Token = base.EncodeSha1(gouuid.NewV4().String()) | ||||
| 	t.TokenHash = hashToken(t.Token, t.TokenSalt) | ||||
| 	t.TokenLastEight = t.Token[len(t.Token)-8:] | ||||
| 	_, err = x.Insert(t) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // GetAccessTokenBySHA returns access token by given sha1.
 | ||||
| func GetAccessTokenBySHA(sha string) (*AccessToken, error) { | ||||
| 	if sha == "" { | ||||
| // GetAccessTokenBySHA returns access token by given token value
 | ||||
| func GetAccessTokenBySHA(token string) (*AccessToken, error) { | ||||
| 	if token == "" { | ||||
| 		return nil, ErrAccessTokenEmpty{} | ||||
| 	} | ||||
| 	t := &AccessToken{Sha1: sha} | ||||
| 	has, err := x.Get(t) | ||||
| 	if len(token) < 8 { | ||||
| 		return nil, ErrAccessTokenNotExist{token} | ||||
| 	} | ||||
| 	var tokens []AccessToken | ||||
| 	lastEight := token[len(token)-8:] | ||||
| 	err := x.Table(&AccessToken{}).Where("token_last_eight = ?", lastEight).Find(&tokens) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} else if !has { | ||||
| 		return nil, ErrAccessTokenNotExist{sha} | ||||
| 	} else if len(tokens) == 0 { | ||||
| 		return nil, ErrAccessTokenNotExist{token} | ||||
| 	} | ||||
| 	return t, nil | ||||
| 	for _, t := range tokens { | ||||
| 		tempHash := hashToken(token, t.TokenSalt) | ||||
| 		if subtle.ConstantTimeCompare([]byte(t.TokenHash), []byte(tempHash)) == 1 { | ||||
| 			return &t, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, ErrAccessTokenNotExist{token} | ||||
| } | ||||
| 
 | ||||
| // ListAccessTokens returns a list of access tokens belongs to given user.
 | ||||
|  |  | |||
|  | @ -29,11 +29,12 @@ func TestNewAccessToken(t *testing.T) { | |||
| 
 | ||||
| func TestGetAccessTokenBySHA(t *testing.T) { | ||||
| 	assert.NoError(t, PrepareTestDatabase()) | ||||
| 	token, err := GetAccessTokenBySHA("hash1") | ||||
| 	token, err := GetAccessTokenBySHA("d2c6c1ba3890b309189a8e618c72a162e4efbf36") | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, int64(1), token.UID) | ||||
| 	assert.Equal(t, "Token A", token.Name) | ||||
| 	assert.Equal(t, "hash1", token.Sha1) | ||||
| 	assert.Equal(t, "2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f", token.TokenHash) | ||||
| 	assert.Equal(t, "e4efbf36", token.TokenLastEight) | ||||
| 
 | ||||
| 	token, err = GetAccessTokenBySHA("notahash") | ||||
| 	assert.Error(t, err) | ||||
|  | @ -69,7 +70,7 @@ func TestListAccessTokens(t *testing.T) { | |||
| 
 | ||||
| func TestUpdateAccessToken(t *testing.T) { | ||||
| 	assert.NoError(t, PrepareTestDatabase()) | ||||
| 	token, err := GetAccessTokenBySHA("hash2") | ||||
| 	token, err := GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c") | ||||
| 	assert.NoError(t, err) | ||||
| 	token.Name = "Token Z" | ||||
| 
 | ||||
|  | @ -80,7 +81,7 @@ func TestUpdateAccessToken(t *testing.T) { | |||
| func TestDeleteAccessTokenByID(t *testing.T) { | ||||
| 	assert.NoError(t, PrepareTestDatabase()) | ||||
| 
 | ||||
| 	token, err := GetAccessTokenBySHA("hash2") | ||||
| 	token, err := GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c") | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, int64(1), token.UID) | ||||
| 
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ import ( | |||
| 	"crypto/md5" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/sha1" | ||||
| 	"crypto/sha256" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
|  | @ -54,6 +55,13 @@ func EncodeSha1(str string) string { | |||
| 	return hex.EncodeToString(h.Sum(nil)) | ||||
| } | ||||
| 
 | ||||
| // EncodeSha256 string to sha1 hex value.
 | ||||
| func EncodeSha256(str string) string { | ||||
| 	h := sha256.New() | ||||
| 	h.Write([]byte(str)) | ||||
| 	return hex.EncodeToString(h.Sum(nil)) | ||||
| } | ||||
| 
 | ||||
| // ShortSha is basically just truncating.
 | ||||
| // It is DEPRECATED and will be removed in the future.
 | ||||
| func ShortSha(sha1 string) string { | ||||
|  |  | |||
|  | @ -53,6 +53,13 @@ func TestEncodeSha1(t *testing.T) { | |||
| 	) | ||||
| } | ||||
| 
 | ||||
| func TestEncodeSha256(t *testing.T) { | ||||
| 	assert.Equal(t, | ||||
| 		"c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2", | ||||
| 		EncodeSha256("foobar"), | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| func TestShortSha(t *testing.T) { | ||||
| 	assert.Equal(t, "veryverylo", ShortSha("veryverylong")) | ||||
| } | ||||
|  |  | |||
|  | @ -39,7 +39,7 @@ func ListAccessTokens(ctx *context.APIContext) { | |||
| 		apiTokens[i] = &api.AccessToken{ | ||||
| 			ID:             tokens[i].ID, | ||||
| 			Name:           tokens[i].Name, | ||||
| 			Sha1: tokens[i].Sha1, | ||||
| 			TokenLastEight: tokens[i].TokenLastEight, | ||||
| 		} | ||||
| 	} | ||||
| 	ctx.JSON(200, &apiTokens) | ||||
|  | @ -82,7 +82,7 @@ func CreateAccessToken(ctx *context.APIContext, form api.CreateAccessTokenOption | |||
| 	} | ||||
| 	ctx.JSON(201, &api.AccessToken{ | ||||
| 		Name:  t.Name, | ||||
| 		Sha1: t.Sha1, | ||||
| 		Token: t.Token, | ||||
| 		ID:    t.ID, | ||||
| 	}) | ||||
| } | ||||
|  |  | |||
|  | @ -49,7 +49,7 @@ func ApplicationsPost(ctx *context.Context, form auth.NewAccessTokenForm) { | |||
| 	} | ||||
| 
 | ||||
| 	ctx.Flash.Success(ctx.Tr("settings.generate_token_success")) | ||||
| 	ctx.Flash.Info(t.Sha1) | ||||
| 	ctx.Flash.Info(t.Token) | ||||
| 
 | ||||
| 	ctx.Redirect(setting.AppSubURL + "/user/settings/applications") | ||||
| } | ||||
|  |  | |||
|  | @ -9458,8 +9458,11 @@ | |||
|   }, | ||||
|   "responses": { | ||||
|     "AccessToken": { | ||||
|       "description": "AccessToken represents a API access token.", | ||||
|       "description": "AccessToken represents an API access token.", | ||||
|       "headers": { | ||||
|         "hashed_token": { | ||||
|           "type": "string" | ||||
|         }, | ||||
|         "id": { | ||||
|           "type": "integer", | ||||
|           "format": "int64" | ||||
|  | @ -9467,7 +9470,10 @@ | |||
|         "name": { | ||||
|           "type": "string" | ||||
|         }, | ||||
|         "sha1": { | ||||
|         "token": { | ||||
|           "type": "string" | ||||
|         }, | ||||
|         "token_last_eight": { | ||||
|           "type": "string" | ||||
|         } | ||||
|       } | ||||
|  |  | |||
							
								
								
									
										7
									
								
								vendor/code.gitea.io/sdk/gitea/user_app.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/code.gitea.io/sdk/gitea/user_app.go
									
									
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,4 +1,5 @@ | |||
| // 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.
 | ||||
| 
 | ||||
|  | @ -17,12 +18,14 @@ func BasicAuthEncode(user, pass string) string { | |||
| 	return base64.StdEncoding.EncodeToString([]byte(user + ":" + pass)) | ||||
| } | ||||
| 
 | ||||
| // AccessToken represents a API access token.
 | ||||
| // AccessToken represents an API access token.
 | ||||
| // swagger:response AccessToken
 | ||||
| type AccessToken struct { | ||||
| 	ID             int64  `json:"id"` | ||||
| 	Name           string `json:"name"` | ||||
| 	Sha1 string `json:"sha1"` | ||||
| 	Token          string `json:"token"` | ||||
| 	HashedToken    string `json:"hashed_token"` | ||||
| 	TokenLastEight string `json:"token_last_eight"` | ||||
| } | ||||
| 
 | ||||
| // AccessTokenList represents a list of API access token.
 | ||||
|  |  | |||
							
								
								
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							|  | @ -1,4 +1,4 @@ | |||
| # code.gitea.io/sdk v0.0.0-20190416172854-7d954d775498 | ||||
| # code.gitea.io/sdk v0.0.0-20190419065346-2858b80da5f7 | ||||
| code.gitea.io/sdk/gitea | ||||
| # github.com/BurntSushi/toml v0.3.1 | ||||
| github.com/BurntSushi/toml | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue