package data import ( "strings" "time" twofactor "git.wntrmute.dev/kyle/goutils/twofactor" ) const totpPeriod = 30 // builtinTOTPValidator delegates TOTP validation to goutils/twofactor. type builtinTOTPValidator struct{} func (builtinTOTPValidator) Validate(secret, code string, at time.Time, window int) bool { if secret == "" || code == "" { return false } // Normalize secret similar to common authenticator apps: remove spaces and uppercase. norm := strings.ToUpper(strings.ReplaceAll(secret, " ", "")) norm = twofactor.Pad(norm) otp, err := twofactor.NewGoogleTOTP(norm) if err != nil || otp == nil { return false } // Compute the base counter for the provided time (period 30s, start 0). base := uint64(at.Unix()&unsignedMask64) / totpPeriod // #nosec G115 - masked off overflow // Check +/- window steps. for i := -window; i <= window; i++ { var ctr uint64 if i < 0 { // Guard underflow. offs := uint64(-i) if offs > base { continue } ctr = base - offs } else { ctr = base + uint64(i) } if otp.OATH.OTP(ctr) == code { return true } } return false }