<commit_before>package database

import (
	"crypto"
	log "github.com/Sirupsen/logrus"
	"github.com/hkparker/Wave/helpers"
	"github.com/jinzhu/gorm"
	"github.com/sec51/twofactor"
	"golang.org/x/crypto/bcrypt"
	"time"
)

type User struct {
	gorm.Model
	Name               string
	Password           <PASSWORD>
	Email              string `sql:"not null;unique"`
	Admin              bool
	Sessions           []Session
	OTPData            []byte
	PasswordResetToken string
	AccountSetupToken  string
	OTPResetNextLogin  bool
}

func CreateUser(email string) (err error) {
	otp, err := twofactor.NewTOTP(email, "Wave", crypto.SHA512, 8)
	if err != nil {
		return
	}
	otp_data, err := otp.ToBytes()
	if err != nil {
		return
	}
	user := User{
		Email:             email,
		OTPData:           otp_data,
		AccountSetupToken: helpers.RandomString(),
	}
	db_err := DB().Create(&user)
	if db_err.Error != nil {
		err = db_err.Error
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("error_saving_user")
	} else {
		//user.EmailRegistration()
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"email":  "account_register",
		}).Info("email_sent")
	}
	log.WithFields(log.Fields{
		"UserID": user.ID,
		"email":  user.Email,
	}).Info("user_created")
	return
}

func (user *User) SetPassword(password string) (err error) {
	pw_data, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("bcrypt_error")
		return
	}
	user.Password = <PASSWORD>
	DB().Save(&user)
	log.WithFields(log.Fields{
		"UserID": user.ID,
	}).Info("user_password_set")
	return
}

func (user *User) ResetPassword() (err error) {
	user.DestroyAllSessions()
	user.PasswordResetToken = helpers.RandomString()
	db_err := DB().Save(&user)
	if db_err.Error != nil {
		log.WithFields(log.Fields{
			"UserID": user.ID,
		}).Warn("error_saving_user")
		err = db_err.Error
	} else {
		//user.EmailPasswordReset(user.PasswordResetToken)
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"email":  "password_reset",
		}).Info("email_sent")
	}
	log.WithFields(log.Fields{
		"UserID": user.ID,
	}).Info("user_password_reset")
	return
}

func (user *User) ResetTwoFactor() (err error) {
	user.DestroyAllSessions()
	otp, err := twofactor.NewTOTP(user.Email, "Wave", crypto.SHA512, 8)
	if err != nil {
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("otp_error")
		return
	}
	otp_data, err := otp.ToBytes()
	if err != nil {
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("otp_error")
		return
	}
	user.OTPData = otp_data
	user.OTPResetNextLogin = true
	db_err := DB().Save(&user)
	if db_err.Error != nil {
		err = db_err.Error
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("error_saving_user")
		return
	}
	log.WithFields(log.Fields{
		"UserID": user.ID,
	}).Info("two_factor_reset")
	return
}

func ValidAuthentication(email, password, token string) (valid bool) {
	valid = false
	minimum_time := 500 * time.Millisecond
	start := time.Now()

	var user User
	db_err := DB().First(&user, "Email = ?", email)
	if db_err.Error == nil {
		err := bcrypt.CompareHashAndPassword(user.Password, []byte(password))
		if err == nil {
			otp, err := twofactor.TOTPFromBytes(user.OTPData, "Wave")
			if err == nil {
				err = otp.Validate(token)
				if err == nil || helpers.Development() {
					valid = true
				}
			}
		}
	}

	duration := time.Since(start)
	if duration < minimum_time {
		time.Sleep(minimum_time - duration)
	}
	return
}

func (user *User) NewSession() (wave_session string, err error) {
	now := time.Now()
	wave_session = helpers.RandomString()
	session := Session{
		UserID:            user.ID,
		OriginallyCreated: now,
		LastUsed:          now,
		Cookie:            wave_session,
	}
	user.Sessions = append(user.Sessions, session)
	DB().Save(&user)
	log.WithFields(log.Fields{
		"UserID": user.ID,
		"Cookie": wave_session,
	}).Info("session_created")
	return
}

func (user *User) DestroyAllSessions() {
	user.Sessions = []Session{}
	DB().Save(&user)
	for session := range user.Sessions {
		DB().Unscoped().Delete(&session)
	}
}<commit_msg>forking twofactor to support key storage in postgres<commit_after>package database

import (
	"crypto"
	log "github.com/Sirupsen/logrus"
	"github.com/Wave-IDS/twofactor"
	"github.com/hkparker/Wave/helpers"
	"github.com/jinzhu/gorm"
	"golang.org/x/crypto/bcrypt"
	"time"
)

type User struct {
	gorm.Model
	Name               string
	Password           <PASSWORD>
	Email              string `sql:"not null;unique"`
	Admin              bool
	Sessions           []Session
	OTPData            []byte
	PasswordResetToken string
	AccountSetupToken  string
	OTPResetNextLogin  bool
}

func CreateUser(email string) (err error) {
	otp, err := twofactor.NewTOTP(email, "Wave", crypto.SHA512, 8)
	if err != nil {
		return
	}
	otp_data, err := otp.ToBytes(DB())
	if err != nil {
		return
	}
	user := User{
		Email:             email,
		OTPData:           otp_data,
		AccountSetupToken: helpers.RandomString(),
	}
	db_err := DB().Create(&user)
	if db_err.Error != nil {
		err = db_err.Error
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("error_saving_user")
	} else {
		//user.EmailRegistration()
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"email":  "account_register",
		}).Info("email_sent")
	}
	log.WithFields(log.Fields{
		"UserID": user.ID,
		"email":  user.Email,
	}).Info("user_created")
	return
}

func (user *User) SetPassword(password string) (err error) {
	pw_data, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("bcrypt_error")
		return
	}
	user.Password = <PASSWORD>
	DB().Save(&user)
	log.WithFields(log.Fields{
		"UserID": user.ID,
	}).Info("user_password_set")
	return
}

func (user *User) ResetPassword() (err error) {
	user.DestroyAllSessions()
	user.PasswordResetToken = helpers.RandomString()
	db_err := DB().Save(&user)
	if db_err.Error != nil {
		log.WithFields(log.Fields{
			"UserID": user.ID,
		}).Warn("error_saving_user")
		err = db_err.Error
	} else {
		//user.EmailPasswordReset(user.PasswordResetToken)
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"email":  "password_reset",
		}).Info("email_sent")
	}
	log.WithFields(log.Fields{
		"UserID": user.ID,
	}).Info("user_password_reset")
	return
}

func (user *User) ResetTwoFactor() (err error) {
	user.DestroyAllSessions()
	otp, err := twofactor.NewTOTP(user.Email, "Wave", crypto.SHA512, 8)
	if err != nil {
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("otp_error")
		return
	}
	otp_data, err := otp.ToBytes(DB())
	if err != nil {
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("otp_error")
		return
	}
	user.OTPData = otp_data
	user.OTPResetNextLogin = true
	db_err := DB().Save(&user)
	if db_err.Error != nil {
		err = db_err.Error
		log.WithFields(log.Fields{
			"UserID": user.ID,
			"error":  err,
		}).Warn("error_saving_user")
		return
	}
	log.WithFields(log.Fields{
		"UserID": user.ID,
	}).Info("two_factor_reset")
	return
}

func ValidAuthentication(email, password, token string) (valid bool) {
	valid = false

	var user User
	db_err := DB().First(&user, "Email = ?", email)
	if db_err.Error != nil {
		return
	}

	err := bcrypt.CompareHashAndPassword(user.Password, []byte(password))
	if err != nil {
		return
	}

	otp, err := twofactor.TOTPFromBytes(user.OTPData, "Wave", DB())
	if err != nil {
		return
	}

	err = otp.Validate(token)
	if err == nil || helpers.Development() {
		valid = true
	}

	return
}

func (user *User) NewSession() (wave_session string, err error) {
	now := time.Now()
	wave_session = helpers.RandomString()
	session := Session{
		UserID:            user.ID,
		OriginallyCreated: now,
		LastUsed:          now,
		Cookie:            wave_session,
	}
	user.Sessions = append(user.Sessions, session)
	DB().Save(&user)
	log.WithFields(log.Fields{
		"UserID": user.ID,
		"Cookie": wave_session,
	}).Info("session_created")
	return
}

func (user *User) DestroyAllSessions() {
	user.Sessions = []Session{}
	DB().Save(&user)
	for session := range user.Sessions {
		DB().Unscoped().Delete(&session)
	}
}
{'fraction_non_alphanumeric': 0.15826564739608218, 'fraction_numerical': 0.002508361204013378, 'mean_word_length': 3.5431361909929464, 'pattern_counts': {'":': 44, '<': 8, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1497391', 'n_tokens_mistral': 3346, 'n_tokens_neox': 3133, 'n_words': 623}