code.gitea.io/gitea@v1.22.3/models/migrations/v1_6/v71.go (about)

     1  // Copyright 2018 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package v1_6 //nolint
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"code.gitea.io/gitea/models/migrations/base"
    10  	"code.gitea.io/gitea/modules/timeutil"
    11  	"code.gitea.io/gitea/modules/util"
    12  
    13  	"xorm.io/xorm"
    14  )
    15  
    16  func AddScratchHash(x *xorm.Engine) error {
    17  	// TwoFactor see models/twofactor.go
    18  	type TwoFactor struct {
    19  		ID               int64 `xorm:"pk autoincr"`
    20  		UID              int64 `xorm:"UNIQUE"`
    21  		Secret           string
    22  		ScratchToken     string
    23  		ScratchSalt      string
    24  		ScratchHash      string
    25  		LastUsedPasscode string             `xorm:"VARCHAR(10)"`
    26  		CreatedUnix      timeutil.TimeStamp `xorm:"INDEX created"`
    27  		UpdatedUnix      timeutil.TimeStamp `xorm:"INDEX updated"`
    28  	}
    29  
    30  	if err := x.Sync(new(TwoFactor)); err != nil {
    31  		return fmt.Errorf("Sync: %w", err)
    32  	}
    33  
    34  	sess := x.NewSession()
    35  	defer sess.Close()
    36  
    37  	if err := sess.Begin(); err != nil {
    38  		return err
    39  	}
    40  
    41  	// transform all tokens to hashes
    42  	const batchSize = 100
    43  	for start := 0; ; start += batchSize {
    44  		tfas := make([]*TwoFactor, 0, batchSize)
    45  		if err := sess.Limit(batchSize, start).Find(&tfas); err != nil {
    46  			return err
    47  		}
    48  		if len(tfas) == 0 {
    49  			break
    50  		}
    51  
    52  		for _, tfa := range tfas {
    53  			// generate salt
    54  			salt, err := util.CryptoRandomString(10)
    55  			if err != nil {
    56  				return err
    57  			}
    58  			tfa.ScratchSalt = salt
    59  			tfa.ScratchHash = base.HashToken(tfa.ScratchToken, salt)
    60  
    61  			if _, err := sess.ID(tfa.ID).Cols("scratch_salt, scratch_hash").Update(tfa); err != nil {
    62  				return fmt.Errorf("couldn't add in scratch_hash and scratch_salt: %w", err)
    63  			}
    64  		}
    65  	}
    66  
    67  	// Commit and begin new transaction for dropping columns
    68  	if err := sess.Commit(); err != nil {
    69  		return err
    70  	}
    71  	if err := sess.Begin(); err != nil {
    72  		return err
    73  	}
    74  
    75  	if err := base.DropTableColumns(sess, "two_factor", "scratch_token"); err != nil {
    76  		return err
    77  	}
    78  	return sess.Commit()
    79  }