diff options
Diffstat (limited to 'utils')
| -rw-r--r-- | utils/auth/auth.go | 26 | ||||
| -rw-r--r-- | utils/email/email.go | 124 | ||||
| -rw-r--r-- | utils/validators/tokens.go | 14 |
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 +} |
