package main import ( "context" "crypto/rand" "database/sql" "encoding/base64" "fmt" "log" "time" ) type Address struct { Id int64 `json:"-"` Street1 string `json:"street1" form:"street1"` Street2 *string `json:"street2,omitempty" form:"street2,omitempty"` City string `json:"city" form:"city"` State *string `json:"state,omitempty" form:"state,omitempty"` PostalCode string `json:"postal_code" form:"postal-code"` Country string `json:"country" form:"country"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` } type User struct { Status int32 `json:"status"` Id int64 `json:"-"` UserName string `json:"user_name" form:"user-id"` ContactName string `json:"contact_name" form:"name"` SecretCodes string `json:"-"` CurrentToken *string `json:"-"` ContactNumber string `json:"contact_number" form:"phone-number"` EmailAddress string `json:"email_address" form:"email"` MailingAddress Address `json:"mailing_address"` RegistrationCode string `json:"-" form:"registration_code"` } func GenerateToken(n int) (string, error) { b := make([]byte, n) if _, err := rand.Read(b); err != nil { return "", fmt.Errorf("reading random bytes: %w\n", err) } return base64.RawURLEncoding.EncodeToString(b), nil } func startCleanupLoop(ctx context.Context, db *sql.DB, interval, ttl time.Duration) { ticker := time.NewTicker(interval) defer ticker.Stop() for { select { case <-ctx.Done(): return case <-ticker.C: if err := cleanupExpired(db, ttl); err != nil { log.Printf("token cleanup error: %v\n", err) } } } } func cleanupExpired(db *sql.DB, ttl time.Duration) error { sqlStmt := ` UPDATE users SET current_token=null,token_creation=null WHERE token_creation < DATE_SUB(NOW(), INTERVAL ? SECOND); ` res, err := db.Exec(sqlStmt, int(ttl.Seconds())) if err != nil { return err } n, _ := res.RowsAffected() log.Printf("Token Cleanup: updated %d rows\n", n) return nil } func generateAESKey(keySize int) ([]byte, error) { key := make([]byte, keySize) _, err := rand.Read(key) if err != nil { return nil, err } return key, nil }