code.gitea.io/gitea@v1.21.7/models/migrations/v1_9/v85.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package v1_9 //nolint
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"code.gitea.io/gitea/models/migrations/base"
    10  	"code.gitea.io/gitea/modules/log"
    11  	"code.gitea.io/gitea/modules/timeutil"
    12  	"code.gitea.io/gitea/modules/util"
    13  
    14  	"xorm.io/xorm"
    15  )
    16  
    17  func HashAppToken(x *xorm.Engine) error {
    18  	// AccessToken see models/token.go
    19  	type AccessToken struct {
    20  		ID             int64 `xorm:"pk autoincr"`
    21  		UID            int64 `xorm:"INDEX"`
    22  		Name           string
    23  		Sha1           string
    24  		Token          string `xorm:"-"`
    25  		TokenHash      string // sha256 of token - we will ensure UNIQUE later
    26  		TokenSalt      string
    27  		TokenLastEight string `xorm:"token_last_eight"`
    28  
    29  		CreatedUnix       timeutil.TimeStamp `xorm:"INDEX created"`
    30  		UpdatedUnix       timeutil.TimeStamp `xorm:"INDEX updated"`
    31  		HasRecentActivity bool               `xorm:"-"`
    32  		HasUsed           bool               `xorm:"-"`
    33  	}
    34  
    35  	// First remove the index
    36  	sess := x.NewSession()
    37  	defer sess.Close()
    38  
    39  	if err := sess.Begin(); err != nil {
    40  		return err
    41  	}
    42  
    43  	if err := sess.Sync(new(AccessToken)); err != nil {
    44  		return fmt.Errorf("Sync: %w", err)
    45  	}
    46  
    47  	if err := sess.Commit(); err != nil {
    48  		return err
    49  	}
    50  
    51  	if err := sess.Begin(); err != nil {
    52  		return err
    53  	}
    54  
    55  	// transform all tokens to hashes
    56  	const batchSize = 100
    57  	for start := 0; ; start += batchSize {
    58  		tokens := make([]*AccessToken, 0, batchSize)
    59  		if err := sess.Limit(batchSize, start).Find(&tokens); err != nil {
    60  			return err
    61  		}
    62  		if len(tokens) == 0 {
    63  			break
    64  		}
    65  
    66  		for _, token := range tokens {
    67  			// generate salt
    68  			salt, err := util.CryptoRandomString(10)
    69  			if err != nil {
    70  				return err
    71  			}
    72  			token.TokenSalt = salt
    73  			token.TokenHash = base.HashToken(token.Sha1, salt)
    74  			if len(token.Sha1) < 8 {
    75  				log.Warn("Unable to transform token %s with name %s belonging to user ID %d, skipping transformation", token.Sha1, token.Name, token.UID)
    76  				continue
    77  			}
    78  			token.TokenLastEight = token.Sha1[len(token.Sha1)-8:]
    79  			token.Sha1 = "" // ensure to blank out column in case drop column doesn't work
    80  
    81  			if _, err := sess.ID(token.ID).Cols("token_hash, token_salt, token_last_eight, sha1").Update(token); err != nil {
    82  				return fmt.Errorf("couldn't add in sha1, token_hash, token_salt and token_last_eight: %w", err)
    83  			}
    84  
    85  		}
    86  	}
    87  
    88  	// Commit and begin new transaction for dropping columns
    89  	if err := sess.Commit(); err != nil {
    90  		return err
    91  	}
    92  	if err := sess.Begin(); err != nil {
    93  		return err
    94  	}
    95  
    96  	if err := base.DropTableColumns(sess, "access_token", "sha1"); err != nil {
    97  		return err
    98  	}
    99  	if err := sess.Commit(); err != nil {
   100  		return err
   101  	}
   102  	return resyncHashAppTokenWithUniqueHash(x)
   103  }
   104  
   105  func resyncHashAppTokenWithUniqueHash(x *xorm.Engine) error {
   106  	// AccessToken see models/token.go
   107  	type AccessToken struct {
   108  		TokenHash string `xorm:"UNIQUE"` // sha256 of token - we will ensure UNIQUE later
   109  	}
   110  	sess := x.NewSession()
   111  	defer sess.Close()
   112  	if err := sess.Begin(); err != nil {
   113  		return err
   114  	}
   115  	if err := sess.Sync(new(AccessToken)); err != nil {
   116  		return fmt.Errorf("Sync: %w", err)
   117  	}
   118  	return sess.Commit()
   119  }