2024-05-04 17:06:01 +02:00
|
|
|
package db
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2024-09-30 13:19:01 +02:00
|
|
|
"errors"
|
2024-05-04 17:06:01 +02:00
|
|
|
"fmt"
|
2024-05-09 15:02:43 +02:00
|
|
|
"log"
|
2024-05-04 17:06:01 +02:00
|
|
|
|
2024-09-30 13:19:01 +02:00
|
|
|
"code.lila.network/adoralaura/go-urlsh/internal/misc"
|
2024-05-04 17:06:01 +02:00
|
|
|
"code.lila.network/adoralaura/go-urlsh/models"
|
2024-09-30 13:19:01 +02:00
|
|
|
"github.com/uptrace/bun"
|
2024-05-04 17:06:01 +02:00
|
|
|
)
|
|
|
|
|
2024-05-09 15:02:43 +02:00
|
|
|
// UserHasMFA checks the DB if given models.User has MFA enabled.
|
|
|
|
// Returns (true, nil) if User has MFA enabled, (false, nil) if not.
|
|
|
|
// (false, error) if a DB error happened
|
2024-05-04 17:06:01 +02:00
|
|
|
func UserHasMFA(user models.User) (bool, error) {
|
|
|
|
numrows, err := models.DB.NewSelect().Model((*models.MFAConfig)(nil)).Where("username = ?", user.UserName).Where("active = ?", true).Count(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
return false, fmt.Errorf("[UserHasMFA] error getting MFA count from database: %q", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if numrows >= 1 {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
return false, nil
|
|
|
|
}
|
2024-05-06 15:32:53 +02:00
|
|
|
|
2024-09-30 13:19:01 +02:00
|
|
|
// scratchCodeUnique checks the database if the generated scratch code
|
2024-05-06 15:32:53 +02:00
|
|
|
// is unique (not in the database yet)
|
2024-09-30 13:19:01 +02:00
|
|
|
func scratchCodeIsUnique(db *bun.DB, scratchcode string) bool {
|
2024-05-06 15:32:53 +02:00
|
|
|
var dbitem models.MFAScratchCode
|
2024-09-30 13:19:01 +02:00
|
|
|
numrows, err := db.NewSelect().Model(&dbitem).Where("code = ?", scratchcode).Count(context.Background())
|
2024-05-06 15:32:53 +02:00
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if numrows != 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
2024-05-09 15:02:43 +02:00
|
|
|
|
|
|
|
// RemoveMFAFromDB removes MFA entries for given models.User from the database.
|
|
|
|
// Returns nil on success, error otherwise.
|
|
|
|
func RemoveMFAFromDB(user models.User) error {
|
|
|
|
hasMfa, err := UserHasMFA(user)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("[RemoveMFAFromDB] Error removing MFA from DB for user %v: %w", user.UserName, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !hasMfa {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = models.DB.NewDelete().Model((*models.MFAConfig)(nil)).Where("username = ?", user.UserName).Exec(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err.Error())
|
|
|
|
return fmt.Errorf("[RemoveMFAFromDB] Error removing MFA Config from DB for user %v: %w", user.UserName, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = models.DB.NewDelete().Model((*models.MFAScratchCode)(nil)).Where("username = ?", user.UserName).Exec(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
log.Println(err.Error())
|
|
|
|
return fmt.Errorf("[RemoveMFAFromDB] Error removing MFA scratch codes from DB for user %v: %w", user.UserName, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2024-09-30 13:19:01 +02:00
|
|
|
|
|
|
|
// UserHasFailedMFAAttempt checks the DB for failed MFA Setup attempts
|
|
|
|
// e.g. inactive MFA config
|
|
|
|
func UserHasFailedMFAAttempt(user models.User) (bool, error) {
|
|
|
|
//var mfaconfig models.MFAConfig
|
|
|
|
//numrows, err := models.DB.NewSelect().Model(&mfaconfig).
|
|
|
|
// Where("username = ?", user.UserName).Where("active = ?", false).
|
|
|
|
// Count(context.Background())
|
|
|
|
//if err != nil {
|
|
|
|
// return false, err
|
|
|
|
//}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GenerateNewScratchcodes generates new unique scratch codes, inserts them into the database
|
|
|
|
// and returns the scratch codes as []models.MFAScratchCode, and nil if successful. Returns empty
|
|
|
|
// []models.MFAScratchCode and an error if something failed
|
|
|
|
func GenerateNewScratchcodes(db *bun.DB, user models.User) ([]models.MFAScratchCode, error) {
|
|
|
|
scratchcodes := []models.MFAScratchCode{}
|
|
|
|
scratchcodeFailed := 0
|
|
|
|
|
|
|
|
// generate four unique(!) scratch codes for the user
|
|
|
|
for len(scratchcodes) != 4 {
|
|
|
|
if scratchcodeFailed > 15 {
|
|
|
|
return []models.MFAScratchCode{}, errors.New("failed to generate new scratch codes: maximum tries exceeded")
|
|
|
|
}
|
|
|
|
|
|
|
|
code := misc.RandomString(8)
|
|
|
|
|
|
|
|
if scratchCodeIsUnique(db, code) {
|
|
|
|
scratchcodes = append(scratchcodes, models.MFAScratchCode{
|
|
|
|
IsUsed: false, Code: code, UserName: user.UserName})
|
|
|
|
} else {
|
|
|
|
scratchcodeFailed++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err := db.NewInsert().Model(&scratchcodes).Exec(context.Background())
|
|
|
|
if err != nil {
|
|
|
|
return []models.MFAScratchCode{}, fmt.Errorf("error inserting new scratch codes to DB: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return scratchcodes, nil
|
|
|
|
}
|