all repos — auth-boilerplate @ 16d9372b47e836a365f88331d564d1ac0cf8c25f

A simple Go web-app boilerplate.

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 this link to reset your password: %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}