2018-07-27 15:54:50 +03:00
// 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"
2019-08-15 17:46:21 +03:00
"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/timeutil"
2018-07-27 15:54:50 +03:00
"golang.org/x/crypto/pbkdf2"
2019-10-17 12:26:49 +03:00
"xorm.io/xorm"
2018-07-27 15:54:50 +03:00
)
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
2019-08-15 17:46:21 +03:00
LastUsedPasscode string ` xorm:"VARCHAR(10)" `
CreatedUnix timeutil . TimeStamp ` xorm:"INDEX created" `
UpdatedUnix timeutil . TimeStamp ` xorm:"INDEX updated" `
2018-07-27 15:54:50 +03:00
}
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 )
2018-12-31 16:23:03 +03:00
if err := sess . Limit ( batchSize , start ) . Find ( & tfas ) ; err != nil {
2018-07-27 15:54:50 +03:00
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 )
}