Switch plaintext scratch tokens to use hash instead (#4331)
	
		
	
				
					
				
			
							parent
							
								
									ac968c3c6f
								
							
						
					
					
						commit
						adf3f004b6
					
				@ -0,0 +1,88 @@ | 
				
			||||
// Copyright 2018 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 ( | 
				
			||||
	"crypto/sha256" | 
				
			||||
	"fmt" | 
				
			||||
 | 
				
			||||
	"github.com/go-xorm/xorm" | 
				
			||||
	"golang.org/x/crypto/pbkdf2" | 
				
			||||
 | 
				
			||||
	"code.gitea.io/gitea/modules/generate" | 
				
			||||
	"code.gitea.io/gitea/modules/util" | 
				
			||||
) | 
				
			||||
 | 
				
			||||
func addScratchHash(x *xorm.Engine) error { | 
				
			||||
	// TwoFactor see models/twofactor.go
 | 
				
			||||
	type TwoFactor struct { | 
				
			||||
		ID               int64 `xorm:"pk autoincr"` | 
				
			||||
		UID              int64 `xorm:"UNIQUE"` | 
				
			||||
		Secret           string | 
				
			||||
		ScratchToken     string | 
				
			||||
		ScratchSalt      string | 
				
			||||
		ScratchHash      string | 
				
			||||
		LastUsedPasscode string         `xorm:"VARCHAR(10)"` | 
				
			||||
		CreatedUnix      util.TimeStamp `xorm:"INDEX created"` | 
				
			||||
		UpdatedUnix      util.TimeStamp `xorm:"INDEX updated"` | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	if err := x.Sync2(new(TwoFactor)); err != nil { | 
				
			||||
		return fmt.Errorf("Sync2: %v", err) | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	sess := x.NewSession() | 
				
			||||
	defer sess.Close() | 
				
			||||
 | 
				
			||||
	if err := sess.Begin(); err != nil { | 
				
			||||
		return err | 
				
			||||
	} | 
				
			||||
 | 
				
			||||
	// transform all tokens to hashes
 | 
				
			||||
	const batchSize = 100 | 
				
			||||
	for start := 0; ; start += batchSize { | 
				
			||||
		tfas := make([]*TwoFactor, 0, batchSize) | 
				
			||||
		if err := x.Limit(batchSize, start).Find(&tfas); err != nil { | 
				
			||||
			return err | 
				
			||||
		} | 
				
			||||
		if len(tfas) == 0 { | 
				
			||||
			break | 
				
			||||
		} | 
				
			||||
 | 
				
			||||
		for _, tfa := range tfas { | 
				
			||||
			// generate salt
 | 
				
			||||
			salt, err := generate.GetRandomString(10) | 
				
			||||
			if err != nil { | 
				
			||||
				return err | 
				
			||||
			} | 
				
			||||
			tfa.ScratchSalt = salt | 
				
			||||
			tfa.ScratchHash = hashToken(tfa.ScratchToken, salt) | 
				
			||||
 | 
				
			||||
			if _, err := sess.ID(tfa.ID).Cols("scratch_salt, scratch_hash").Update(tfa); err != nil { | 
				
			||||
				return fmt.Errorf("couldn't add in scratch_hash and scratch_salt: %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, "two_factor", "scratch_token"); err != nil { | 
				
			||||
		return err | 
				
			||||
	} | 
				
			||||
	return sess.Commit() | 
				
			||||
 | 
				
			||||
} | 
				
			||||
 | 
				
			||||
func hashToken(token, salt string) string { | 
				
			||||
	tempHash := pbkdf2.Key([]byte(token), []byte(salt), 10000, 50, sha256.New) | 
				
			||||
	return fmt.Sprintf("%x", tempHash) | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue