aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorBobby <[email protected]>2025-07-13 14:22:20 +0530
committerBobby <[email protected]>2025-07-13 14:22:20 +0530
commit3d7f8602d45583f25e2428bf6f8123453646dc08 (patch)
treeecd707d298099ae9fda55efc3f0d1daf48f7b6e9 /utils
parentbf112649d039f8f02e2135a74d8b506f7c31c784 (diff)
downloadimageboard-3d7f8602d45583f25e2428bf6f8123453646dc08.tar.xz
imageboard-3d7f8602d45583f25e2428bf6f8123453646dc08.zip
registration controllers and email sending support
Diffstat (limited to 'utils')
-rw-r--r--utils/auth/auth.go26
-rw-r--r--utils/email/email.go124
-rw-r--r--utils/validators/tokens.go14
3 files changed, 164 insertions, 0 deletions
diff --git a/utils/auth/auth.go b/utils/auth/auth.go
new file mode 100644
index 0000000..7b8f260
--- /dev/null
+++ b/utils/auth/auth.go
@@ -0,0 +1,26 @@
+package auth
+
+import (
+ "imageboard/models"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+func GetCurrentUser(ctx *fiber.Ctx) *models.User {
+ if user, ok := ctx.Locals("User").(*models.User); ok {
+ return user
+ }
+ return nil
+}
+
+func IsAuthenticated(ctx *fiber.Ctx) bool {
+ return GetCurrentUser(ctx) != nil
+}
+
+func GetRedirectURL(ctx *fiber.Ctx) string {
+ referer := ctx.Get("Referer")
+ if referer != "" && referer != ctx.BaseURL()+"/login" && referer != ctx.BaseURL()+"/register" {
+ return referer
+ }
+ return "/"
+}
diff --git a/utils/email/email.go b/utils/email/email.go
new file mode 100644
index 0000000..fb1d58d
--- /dev/null
+++ b/utils/email/email.go
@@ -0,0 +1,124 @@
+package email
+
+import (
+ "bytes"
+ "fmt"
+ "html/template"
+ "imageboard/config"
+ "imageboard/database"
+ "imageboard/models"
+ "net/smtp"
+ "regexp"
+)
+
+func extractEmailAddress(from string) string {
+ re := regexp.MustCompile(`<([^>]+)>`)
+ matches := re.FindStringSubmatch(from)
+ if len(matches) == 2 {
+ return matches[1]
+ }
+ return from
+}
+
+func SendMail(to, subject, body string) error {
+ var auth smtp.Auth
+ if config.SMTP.Username != "" {
+ auth = smtp.PlainAuth("", config.SMTP.Username, config.SMTP.Password, config.SMTP.Host)
+ } else {
+ auth = nil
+ }
+ fromHeader := config.SMTP.From
+ fromAddress := extractEmailAddress(config.SMTP.From)
+ msg := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\nMIME-Version: 1.0\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n%s",
+ fromHeader, to, subject, body)
+ addr := fmt.Sprintf("%s:%d", config.SMTP.Host, config.SMTP.Port)
+ return smtp.SendMail(addr, auth, fromAddress, []string{to}, []byte(msg))
+}
+
+func SendVerificationEmail(user *models.User) error {
+ token, err := database.GenerateEmailToken(int(user.ID), models.EmailTokenTypeVerification)
+ if err != nil {
+ return fmt.Errorf("failed to generate verification token: %w", err)
+ }
+
+ tmpl, err := template.ParseFiles("templates/email/verification.html")
+ if err != nil {
+ return fmt.Errorf("failed to parse email template: %w", err)
+ }
+ verificationLink := fmt.Sprintf("%s/account/verify?token=%s", config.Server.AppBaseURL, token.Token)
+ data := struct {
+ Username string
+ Appname string
+ Link string
+ }{
+ Username: user.Username,
+ Appname: config.Server.AppName,
+ Link: verificationLink,
+ }
+
+ var body bytes.Buffer
+ if err := tmpl.Execute(&body, data); err != nil {
+ return fmt.Errorf("failed to execute email template: %w", err)
+ }
+
+ subject := fmt.Sprintf("Verify your email for %s", config.Server.AppName)
+ return SendMail(user.Email, subject, body.String())
+}
+
+// func SendPasswordResetEmail(user *models.User) error {
+// token, err := user.GenerateToken(database.DB, models.EmailTokenTypePasswordReset)
+// if err != nil {
+// return fmt.Errorf("failed to generate password reset token: %w", err)
+// }
+
+// tmpl, err := template.ParseFiles("templates/email/password_reset.html")
+// if err != nil {
+// return fmt.Errorf("failed to parse email template: %w", err)
+// }
+// resetLink := fmt.Sprintf("%s/account/reset-password?token=%s", config.Server.AppBaseURL, token.Token)
+// data := struct {
+// Username string
+// Link string
+// }{
+// Username: user.Username,
+// Link: resetLink,
+// }
+
+// var body bytes.Buffer
+// if err := tmpl.Execute(&body, data); err != nil {
+// return fmt.Errorf("failed to execute email template: %w", err)
+// }
+
+// subject := fmt.Sprintf("Password reset for %s", config.Server.AppName)
+// return SendMail(user.Email, subject, body.String())
+// }
+
+// func SendEmailChangeConfirmation(user *models.User, newEmail string) error {
+// token, err := user.GenerateToken(database.DB, models.EmailTokenTypeChangeEmail)
+// if err != nil {
+// return fmt.Errorf("failed to generate email change token: %w", err)
+// }
+
+// tmpl, err := template.ParseFiles("templates/email/email_change.html")
+// if err != nil {
+// return fmt.Errorf("failed to parse email template: %w", err)
+// }
+// confirmLink := fmt.Sprintf("%s/account/confirm-email-change?token=%s&email=%s", config.Server.AppBaseURL, token.Token, newEmail)
+// data := struct {
+// Username string
+// NewEmail string
+// Link string
+// }{
+// Username: user.Username,
+// NewEmail: newEmail,
+// Link: confirmLink,
+// }
+
+// var body bytes.Buffer
+// if err := tmpl.Execute(&body, data); err != nil {
+// return fmt.Errorf("failed to execute email template: %w", err)
+// }
+
+// subject := fmt.Sprintf("Confirm email change for %s", config.Server.AppName)
+// return SendMail(newEmail, subject, body.String())
+// }
diff --git a/utils/validators/tokens.go b/utils/validators/tokens.go
new file mode 100644
index 0000000..f377c2e
--- /dev/null
+++ b/utils/validators/tokens.go
@@ -0,0 +1,14 @@
+package validators
+
+import (
+ "crypto/rand"
+ "encoding/hex"
+)
+
+func GenerateRandomToken() (string, error) {
+ bytes := make([]byte, 32)
+ if _, err := rand.Read(bytes); err != nil {
+ return "", err
+ }
+ return hex.EncodeToString(bytes), nil
+}