2019-11-26 03:55:28 +00:00
|
|
|
package controllers
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"git.kirsle.net/apps/gophertype/pkg/authentication"
|
2022-12-06 05:07:52 +00:00
|
|
|
"git.kirsle.net/apps/gophertype/pkg/console"
|
|
|
|
"git.kirsle.net/apps/gophertype/pkg/constants"
|
2019-11-26 03:55:28 +00:00
|
|
|
"git.kirsle.net/apps/gophertype/pkg/glue"
|
|
|
|
"git.kirsle.net/apps/gophertype/pkg/models"
|
2022-12-06 05:07:52 +00:00
|
|
|
"git.kirsle.net/apps/gophertype/pkg/ratelimit"
|
2019-11-26 03:55:28 +00:00
|
|
|
"git.kirsle.net/apps/gophertype/pkg/responses"
|
|
|
|
"git.kirsle.net/apps/gophertype/pkg/session"
|
|
|
|
"github.com/albrow/forms"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
glue.Register(glue.Endpoint{
|
|
|
|
Path: "/login",
|
|
|
|
Methods: []string{"GET", "POST"},
|
|
|
|
Handler: func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// Template variables.
|
|
|
|
v := responses.NewTemplateVars(w, r)
|
|
|
|
|
|
|
|
// POST handler: create the admin account.
|
|
|
|
for r.Method == http.MethodPost {
|
|
|
|
form, _ := forms.Parse(r)
|
|
|
|
v.FormValues = form.Values
|
|
|
|
|
|
|
|
// Validate form parameters.
|
|
|
|
val := form.Validator()
|
|
|
|
val.Require("email")
|
|
|
|
val.MatchEmail("email")
|
|
|
|
val.Require("password")
|
|
|
|
if val.HasErrors() {
|
|
|
|
v.ValidationError = val.ErrorMap()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2022-12-06 05:07:52 +00:00
|
|
|
// Rate limit failed login attempts.
|
|
|
|
limiter := &ratelimit.Limiter{
|
|
|
|
Namespace: "login",
|
|
|
|
ID: form.Get("email"),
|
|
|
|
Limit: constants.LoginRateLimit,
|
|
|
|
Window: constants.LoginRateLimitWindow,
|
|
|
|
CooldownAt: constants.LoginRateLimitCooldownAt,
|
|
|
|
Cooldown: constants.LoginRateLimitCooldown,
|
|
|
|
}
|
|
|
|
|
2019-11-26 03:55:28 +00:00
|
|
|
// Check authentication.
|
2020-02-18 02:10:35 +00:00
|
|
|
user, err := models.Users.AuthenticateUser(form.Get("email"), form.Get("password"))
|
2019-11-26 03:55:28 +00:00
|
|
|
if err != nil {
|
2022-12-06 05:07:52 +00:00
|
|
|
if err := limiter.Ping(); err != nil {
|
|
|
|
v.Error = err
|
|
|
|
break
|
|
|
|
}
|
2019-11-26 03:55:28 +00:00
|
|
|
v.Error = err
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2022-12-06 05:07:52 +00:00
|
|
|
if err := limiter.Clear(); err != nil {
|
|
|
|
console.Error("Failed to clear the login rate limiter: %s", err)
|
|
|
|
}
|
|
|
|
|
2019-11-26 03:55:28 +00:00
|
|
|
_ = user
|
|
|
|
|
|
|
|
authentication.Login(w, r, user)
|
|
|
|
session.Flash(w, r, "Signed in!")
|
|
|
|
responses.Redirect(w, r, "/") // TODO: next URL
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
responses.RenderTemplate(w, r, "_builtin/users/login.gohtml", v)
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
glue.Register(glue.Endpoint{
|
|
|
|
Path: "/logout",
|
|
|
|
Handler: func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
authentication.Logout(w, r)
|
|
|
|
session.Flash(w, r, "Signed out!")
|
|
|
|
responses.Redirect(w, r, "/")
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|