src/app/functions.go (view raw)
1package app
2
3import (
4 "context"
5 "errors"
6 "fmt"
7 "log"
8 "net/http"
9 "os"
10 "regexp"
11 "strings"
12 "time"
13
14 "github.com/birabittoh/auth-boilerplate/src/email"
15)
16
17const (
18 minUsernameLength = 3
19 maxUsernameLength = 10
20)
21
22var (
23 validUsername = regexp.MustCompile(`^[a-z0-9._-]+$`)
24 validEmail = regexp.MustCompile(`^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$`)
25)
26
27func sanitizeUsername(username string) (string, error) {
28 username = strings.ToLower(username)
29
30 if !validUsername.MatchString(username) || len(username) < minUsernameLength || len(username) > maxUsernameLength {
31 return "", errors.New("invalid username")
32 }
33
34 return username, nil
35}
36
37func sanitizeEmail(email string) (string, error) {
38 email = strings.ToLower(email)
39
40 if !validEmail.MatchString(email) {
41 return "", fmt.Errorf("invalid email")
42 }
43
44 return email, nil
45}
46
47func login(w http.ResponseWriter, userID uint, remember bool) {
48 var duration time.Duration
49 if remember {
50 duration = durationWeek
51 } else {
52 duration = durationDay
53 }
54
55 cookie, err := g.GenerateCookie(duration)
56 if err != nil {
57 http.Error(w, "Could not generate session cookie.", http.StatusInternalServerError)
58 }
59
60 ks.Set(cookie.Value, userID, duration)
61 http.SetCookie(w, cookie)
62}
63
64func loadEmailConfig() *email.Client {
65 address := os.Getenv("APP_SMTP_EMAIL")
66 password := os.Getenv("APP_SMTP_PASSWORD")
67 host := os.Getenv("APP_SMTP_HOST")
68 port := os.Getenv("APP_SMTP_PORT")
69
70 if address == "" || password == "" || host == "" {
71 log.Println("Missing email configuration.")
72 return nil
73 }
74
75 if port == "" {
76 port = "587"
77 }
78
79 return email.NewClient(address, password, host, port)
80}
81
82func sendEmail(mail email.Email) error {
83 if m == nil {
84 return errors.New("email client is not initialized")
85 }
86 return m.Send(mail)
87}
88
89func sendResetEmail(address, token string) {
90 resetURL := fmt.Sprintf("%s/reset-password-confirm?token=%s", baseUrl, token)
91 err := sendEmail(email.Email{
92 To: []string{address},
93 Subject: "Reset password",
94 Body: fmt.Sprintf("Use the following link to reset your password:\n%s", resetURL),
95 })
96 if err != nil {
97 log.Printf("Could not send reset email for %s. Link: %s", address, resetURL)
98 }
99}
100
101func readSessionCookie(r *http.Request) (userID *uint, err error) {
102 cookie, err := r.Cookie("session_token")
103 if err != nil {
104 return
105 }
106 return ks.Get(cookie.Value)
107}
108
109// Middleware to check if the user is logged in
110func loginRequired(next http.HandlerFunc) http.HandlerFunc {
111 return func(w http.ResponseWriter, r *http.Request) {
112 userID, err := readSessionCookie(r)
113 if err != nil {
114 http.Redirect(w, r, "/login", http.StatusFound)
115 return
116 }
117
118 ctx := context.WithValue(r.Context(), userContextKey, *userID)
119 next(w, r.WithContext(ctx))
120 }
121}
122
123func getLoggedUser(r *http.Request) (user User, ok bool) {
124 userID, ok := r.Context().Value(userContextKey).(uint)
125 db.Find(&user, userID)
126 return user, ok
127}