package auth
import (
	"crypto/rand"
	"encoding/base32"
	"fmt"
	"time"
	"github.com/pquerna/otp"
	"github.com/pquerna/otp/totp"
)
type TOTPConfig struct {
	Secret string
	Period uint
}
func GenerateSecret(s string) (*TOTPConfig, error) {
	var secret string
	if s != "" {
		secret = s
	} else {
		
		bytes := make([]byte, 20)
		if _, err := rand.Read(bytes); err != nil {
			return nil, fmt.Errorf("生成随机密钥失败: %v", err)
		}
		
		secret = base32.StdEncoding.EncodeToString(bytes)
	}
	return &TOTPConfig{
		Secret: secret,
		Period: 30, 
	}, nil
}
func (c *TOTPConfig) GenerateCode() (string, error) {
	code, err := totp.GenerateCode(c.Secret, time.Now())
	if err != nil {
		return "", fmt.Errorf("生成验证码失败: %v", err)
	}
	return code, nil
}
func (c *TOTPConfig) ValidateCode(code string) bool {
	return totp.Validate(code, c.Secret)
}
func (c *TOTPConfig) GetQRCodeURL(accountName, issuer string) string {
	key, err := otp.NewKeyFromURL(fmt.Sprintf("otpauth://totp/%s:%s?secret=%s&issuer=%s&period=%d",
		issuer,
		accountName,
		c.Secret,
		issuer,
		c.Period))
	if err != nil {
		return ""
	}
	return key.URL()
}
package main
import (
	"fmt"
	"time"
	"my_otp/auth"
)
func main() {
	
	config, err := auth.GenerateSecret("4MEE7Q2BZBD4G6NC")
	if err != nil {
		panic(err)
	}
	
	fmt.Printf("密钥: %s\n", config.Secret)
	
	qrURL := config.GetQRCodeURL("GitHub:liuxiaobopro", "GitHub")
	fmt.Printf("二维码 URL: %s\n", qrURL)
	
	code, err := config.GenerateCode()
	if err != nil {
		panic(err)
	}
	fmt.Printf("当前验证码: %s\n", code)
	
	isValid := config.ValidateCode(code)
	fmt.Printf("验证结果: %v\n", isValid)
	
	time.Sleep(31 * time.Second)
	for range time.Tick(time.Second * 30) {
		newCode, _ := config.GenerateCode()
		fmt.Printf("新的验证码: %s\n", newCode)
	}
}