mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-11-04 00:11:04 +00:00 
			
		
		
		
	Add the default value of the purpose field to both the table and the migration. The table in v9 and v7 backport already have the default value. ALTER TABLE `forgejo_auth_token` ADD `purpose` TEXT NOT NULL [] - Cannot add a NOT NULL column with default value NULL
		
			
				
	
	
		
			116 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2023 The Forgejo Authors. All rights reserved.
 | 
						|
// SPDX-License-Identifier: MIT
 | 
						|
 | 
						|
package auth
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"crypto/sha256"
 | 
						|
	"encoding/hex"
 | 
						|
	"fmt"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"code.gitea.io/gitea/models/db"
 | 
						|
	"code.gitea.io/gitea/modules/timeutil"
 | 
						|
	"code.gitea.io/gitea/modules/util"
 | 
						|
)
 | 
						|
 | 
						|
type AuthorizationPurpose string
 | 
						|
 | 
						|
var (
 | 
						|
	// Used to store long term authorization tokens.
 | 
						|
	LongTermAuthorization AuthorizationPurpose = "long_term_authorization"
 | 
						|
 | 
						|
	// Used to activate a user account.
 | 
						|
	UserActivation AuthorizationPurpose = "user_activation"
 | 
						|
 | 
						|
	// Used to reset the password.
 | 
						|
	PasswordReset AuthorizationPurpose = "password_reset"
 | 
						|
)
 | 
						|
 | 
						|
// Used to activate the specified email address for a user.
 | 
						|
func EmailActivation(email string) AuthorizationPurpose {
 | 
						|
	return AuthorizationPurpose("email_activation:" + email)
 | 
						|
}
 | 
						|
 | 
						|
// AuthorizationToken represents a authorization token to a user.
 | 
						|
type AuthorizationToken struct {
 | 
						|
	ID              int64  `xorm:"pk autoincr"`
 | 
						|
	UID             int64  `xorm:"INDEX"`
 | 
						|
	LookupKey       string `xorm:"INDEX UNIQUE"`
 | 
						|
	HashedValidator string
 | 
						|
	Purpose         AuthorizationPurpose `xorm:"NOT NULL DEFAULT 'long_term_authorization'"`
 | 
						|
	Expiry          timeutil.TimeStamp
 | 
						|
}
 | 
						|
 | 
						|
// TableName provides the real table name.
 | 
						|
func (AuthorizationToken) TableName() string {
 | 
						|
	return "forgejo_auth_token"
 | 
						|
}
 | 
						|
 | 
						|
func init() {
 | 
						|
	db.RegisterModel(new(AuthorizationToken))
 | 
						|
}
 | 
						|
 | 
						|
// IsExpired returns if the authorization token is expired.
 | 
						|
func (authToken *AuthorizationToken) IsExpired() bool {
 | 
						|
	return authToken.Expiry.AsLocalTime().Before(time.Now())
 | 
						|
}
 | 
						|
 | 
						|
// GenerateAuthToken generates a new authentication token for the given user.
 | 
						|
// It returns the lookup key and validator values that should be passed to the
 | 
						|
// user via a long-term cookie.
 | 
						|
func GenerateAuthToken(ctx context.Context, userID int64, expiry timeutil.TimeStamp, purpose AuthorizationPurpose) (lookupKey, validator string, err error) {
 | 
						|
	// Request 64 random bytes. The first 32 bytes will be used for the lookupKey
 | 
						|
	// and the other 32 bytes will be used for the validator.
 | 
						|
	rBytes, err := util.CryptoRandomBytes(64)
 | 
						|
	if err != nil {
 | 
						|
		return "", "", err
 | 
						|
	}
 | 
						|
	hexEncoded := hex.EncodeToString(rBytes)
 | 
						|
	validator, lookupKey = hexEncoded[64:], hexEncoded[:64]
 | 
						|
 | 
						|
	_, err = db.GetEngine(ctx).Insert(&AuthorizationToken{
 | 
						|
		UID:             userID,
 | 
						|
		Expiry:          expiry,
 | 
						|
		LookupKey:       lookupKey,
 | 
						|
		HashedValidator: HashValidator(rBytes[32:]),
 | 
						|
		Purpose:         purpose,
 | 
						|
	})
 | 
						|
	return lookupKey, validator, err
 | 
						|
}
 | 
						|
 | 
						|
// FindAuthToken will find a authorization token via the lookup key.
 | 
						|
func FindAuthToken(ctx context.Context, lookupKey string, purpose AuthorizationPurpose) (*AuthorizationToken, error) {
 | 
						|
	var authToken AuthorizationToken
 | 
						|
	has, err := db.GetEngine(ctx).Where("lookup_key = ? AND purpose = ?", lookupKey, purpose).Get(&authToken)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	} else if !has {
 | 
						|
		return nil, fmt.Errorf("lookup key %q: %w", lookupKey, util.ErrNotExist)
 | 
						|
	}
 | 
						|
	return &authToken, nil
 | 
						|
}
 | 
						|
 | 
						|
// DeleteAuthToken will delete the authorization token.
 | 
						|
func DeleteAuthToken(ctx context.Context, authToken *AuthorizationToken) error {
 | 
						|
	_, err := db.DeleteByBean(ctx, authToken)
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// DeleteAuthTokenByUser will delete all authorization tokens for the user.
 | 
						|
func DeleteAuthTokenByUser(ctx context.Context, userID int64) error {
 | 
						|
	if userID == 0 {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	_, err := db.DeleteByBean(ctx, &AuthorizationToken{UID: userID})
 | 
						|
	return err
 | 
						|
}
 | 
						|
 | 
						|
// HashValidator will return a hexified hashed version of the validator.
 | 
						|
func HashValidator(validator []byte) string {
 | 
						|
	h := sha256.New()
 | 
						|
	h.Write(validator)
 | 
						|
	return hex.EncodeToString(h.Sum(nil))
 | 
						|
}
 |