package utils import ( "crypto/rand" "encoding/base64" "fmt" "time" "gopkg.in/gomail.v2" ) type EmailVerificationData struct { Token string `json:"token"` Email string `json:"email"` UserID string `json:"user_id"` ExpiresAt int64 `json:"expires_at"` Used bool `json:"used"` CreatedAt int64 `json:"created_at"` } const ( EMAIL_VERIFICATION_TOKEN_EXPIRY = 24 * time.Hour EMAIL_VERIFICATION_TOKEN_LENGTH = 32 ) func GenerateEmailVerificationToken() (string, error) { bytes := make([]byte, EMAIL_VERIFICATION_TOKEN_LENGTH) _, err := rand.Read(bytes) if err != nil { return "", fmt.Errorf("failed to generate email verification token: %v", err) } return base64.URLEncoding.EncodeToString(bytes), nil } func StoreEmailVerificationToken(email, userID, token string) error { key := fmt.Sprintf("email_verification:%s", email) DeleteCache(key) data := EmailVerificationData{ Token: token, Email: email, UserID: userID, ExpiresAt: time.Now().Add(EMAIL_VERIFICATION_TOKEN_EXPIRY).Unix(), Used: false, CreatedAt: time.Now().Unix(), } return SetCache(key, data, EMAIL_VERIFICATION_TOKEN_EXPIRY) } func ValidateEmailVerificationToken(email, inputToken string) (*EmailVerificationData, error) { key := fmt.Sprintf("email_verification:%s", email) var data EmailVerificationData err := GetCache(key, &data) if err != nil { return nil, fmt.Errorf("token verifikasi tidak ditemukan atau sudah kadaluarsa") } if time.Now().Unix() > data.ExpiresAt { DeleteCache(key) return nil, fmt.Errorf("token verifikasi sudah kadaluarsa") } if data.Used { return nil, fmt.Errorf("token verifikasi sudah digunakan") } // Validate token if !ConstantTimeCompare(data.Token, inputToken) { return nil, fmt.Errorf("token verifikasi tidak valid") } return &data, nil } // Mark email verification token as used func MarkEmailVerificationTokenAsUsed(email string) error { key := fmt.Sprintf("email_verification:%s", email) var data EmailVerificationData err := GetCache(key, &data) if err != nil { return err } data.Used = true remaining := time.Until(time.Unix(data.ExpiresAt, 0)) return SetCache(key, data, remaining) } // Check if email verification token exists and still valid func IsEmailVerificationTokenValid(email string) bool { key := fmt.Sprintf("email_verification:%s", email) var data EmailVerificationData err := GetCache(key, &data) if err != nil { return false } return time.Now().Unix() <= data.ExpiresAt && !data.Used } // Get remaining email verification token time func GetEmailVerificationTokenRemainingTime(email string) (time.Duration, error) { key := fmt.Sprintf("email_verification:%s", email) var data EmailVerificationData err := GetCache(key, &data) if err != nil { return 0, err } remaining := time.Until(time.Unix(data.ExpiresAt, 0)) if remaining < 0 { return 0, fmt.Errorf("token expired") } return remaining, nil } // Send email verification email func (e *EmailService) SendEmailVerificationEmail(email, name, token string) error { // Create verification URL - in real app this would be frontend URL verificationURL := fmt.Sprintf("http://localhost:3000/verify-email?token=%s&email=%s", token, email) m := gomail.NewMessage() m.SetHeader("From", m.FormatAddress(e.from, e.fromName)) m.SetHeader("To", email) m.SetHeader("Subject", "Verifikasi Email Administrator - Rijig") // Email template body := fmt.Sprintf(`

✅ Verifikasi Email

🎉

Selamat %s!

Akun Administrator Anda telah berhasil dibuat. Untuk mengaktifkan akun dan mulai menggunakan sistem Rijig, silakan verifikasi email Anda dengan mengklik tombol di bawah ini:

Verifikasi Email Saya

Atau copy paste link berikut ke browser Anda:

%s

Informasi Penting:

  • Link verifikasi berlaku selama 24 jam
  • Setelah verifikasi, Anda dapat login ke sistem
  • Link hanya dapat digunakan sekali
  • Jangan bagikan link ini kepada siapapun

Langkah selanjutnya setelah verifikasi:

  1. Login menggunakan email dan password
  2. Masukkan kode OTP yang dikirim ke email
  3. Mulai menggunakan sistem Rijig

Jika Anda tidak membuat akun ini, abaikan email ini.

`, name, verificationURL, verificationURL) m.SetBody("text/html", body) d := gomail.NewDialer(e.host, e.port, e.username, e.password) if err := d.DialAndSend(m); err != nil { return fmt.Errorf("failed to send email verification email: %v", err) } return nil }