Welcome page on first login or after password change
This commit is contained in:
parent
16ca31f27a
commit
eb02ba5ba5
7 changed files with 230 additions and 6 deletions
119
controllers/welcome.go
Normal file
119
controllers/welcome.go
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.readonly.ch/bouzoure/popvaud-people/helpers"
|
||||||
|
"git.readonly.ch/bouzoure/popvaud-people/models"
|
||||||
|
"github.com/go-playground/validator"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WelcomeValidation struct {
|
||||||
|
Email string `validate:"required,min=6,max=100,email"`
|
||||||
|
Name string `validate:"required,min=2,max=100"`
|
||||||
|
Password string `validate:"required,min=12,max=100"`
|
||||||
|
PasswordVerify string `validate:"required,eqfield=Password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func WelcomePage(c *fiber.Ctx) error {
|
||||||
|
db, err := helpers.GetDatabase()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userid, err := helpers.GetSessionUserId(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
result := db.First(&user, "id = ?", userid)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.SkipWelcome {
|
||||||
|
return fiber.NewError(fiber.StatusForbidden, "Forbidden")
|
||||||
|
}
|
||||||
|
|
||||||
|
var formErrors []string
|
||||||
|
emailUpdate := user.Email == "admin@invalid.tld"
|
||||||
|
|
||||||
|
if c.Method() == "POST" {
|
||||||
|
data := WelcomeValidation{
|
||||||
|
Email: c.FormValue("email", user.Email),
|
||||||
|
Name: c.FormValue("name"),
|
||||||
|
Password: c.FormValue("password"),
|
||||||
|
PasswordVerify: c.FormValue("password-verify"),
|
||||||
|
}
|
||||||
|
|
||||||
|
validate := validator.New()
|
||||||
|
validErrs := validate.Struct(data)
|
||||||
|
|
||||||
|
user.Email = data.Email
|
||||||
|
user.Name = data.Name
|
||||||
|
|
||||||
|
if validErrs == nil {
|
||||||
|
passwordHash, err := helpers.HashPassword(data.Password)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Password = passwordHash
|
||||||
|
user.SkipWelcome = true
|
||||||
|
|
||||||
|
result = db.Save(&user)
|
||||||
|
if result.Error != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectId := c.Query("redirect")
|
||||||
|
redirectUrl := "/"
|
||||||
|
|
||||||
|
if len(redirectId) > 0 {
|
||||||
|
sess, err := helpers.GetSessionStore(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectKey := fmt.Sprintf("redirect-%s", redirectId)
|
||||||
|
redirectVal := sess.Get(redirectKey)
|
||||||
|
|
||||||
|
if redirectVal != nil {
|
||||||
|
redirectUrl = redirectVal.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Redirect(redirectUrl)
|
||||||
|
} else {
|
||||||
|
for _, validErr := range validErrs.(validator.ValidationErrors) {
|
||||||
|
if validErr.Field() == "Email" {
|
||||||
|
formErrors = append(formErrors, "L'adresse email doit être valide.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if validErr.Field() == "Name" {
|
||||||
|
formErrors = append(formErrors, "Le nom doit contenir entre 2 et 100 caractères.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if validErr.Field() == "Password" {
|
||||||
|
formErrors = append(formErrors, "Le mot de passe doit contenir entre 12 et 100 caractères.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if validErr.Field() == "PasswordVerify" {
|
||||||
|
formErrors = append(formErrors, "Les mots de passe doivent correspondre.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Render("welcome", fiber.Map{
|
||||||
|
"PageTitle": "Paramètres du compte",
|
||||||
|
"Email": user.Email,
|
||||||
|
"Name": user.Name,
|
||||||
|
"EmailUpdate": emailUpdate,
|
||||||
|
"FormErrors": strings.Join(formErrors, "<br>"),
|
||||||
|
}, "layouts/main")
|
||||||
|
}
|
||||||
4
go.mod
4
go.mod
|
|
@ -26,6 +26,9 @@ require (
|
||||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator v9.31.0+incompatible // indirect
|
||||||
github.com/gofiber/template v1.8.3 // indirect
|
github.com/gofiber/template v1.8.3 // indirect
|
||||||
github.com/gofiber/utils v1.1.0 // indirect
|
github.com/gofiber/utils v1.1.0 // indirect
|
||||||
github.com/gofiber/utils/v2 v2.0.0-beta.3 // indirect
|
github.com/gofiber/utils/v2 v2.0.0-beta.3 // indirect
|
||||||
|
|
@ -39,6 +42,7 @@ require (
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/klauspost/compress v1.17.2 // indirect
|
github.com/klauspost/compress v1.17.2 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
|
|
|
||||||
8
go.sum
8
go.sum
|
|
@ -46,6 +46,12 @@ github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9g
|
||||||
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
|
||||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA=
|
||||||
|
github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig=
|
||||||
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
|
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
|
||||||
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
||||||
github.com/gofiber/storage/badger/v2 v2.0.1 h1:iIB5Dh2dypJjdEruYgBf7H4l5a98R5pVKVLk5wbY5bo=
|
github.com/gofiber/storage/badger/v2 v2.0.1 h1:iIB5Dh2dypJjdEruYgBf7H4l5a98R5pVKVLk5wbY5bo=
|
||||||
|
|
@ -122,6 +128,8 @@ github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3x
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
|
|
||||||
3
main.go
3
main.go
|
|
@ -82,12 +82,15 @@ func main() {
|
||||||
// Middlewares
|
// Middlewares
|
||||||
app.Use(middlewares.AuthMiddleware)
|
app.Use(middlewares.AuthMiddleware)
|
||||||
app.Use("/login", middlewares.DenyAuthMiddleware)
|
app.Use("/login", middlewares.DenyAuthMiddleware)
|
||||||
|
app.Use(middlewares.WelcomeMiddleware)
|
||||||
|
|
||||||
// Controllers
|
// Controllers
|
||||||
app.Get("/", controllers.Homepage)
|
app.Get("/", controllers.Homepage)
|
||||||
app.Get("/login", controllers.LoginForm)
|
app.Get("/login", controllers.LoginForm)
|
||||||
app.Post("/login", controllers.LoginProcess)
|
app.Post("/login", controllers.LoginProcess)
|
||||||
app.Get("/logout", controllers.LogoutProcess)
|
app.Get("/logout", controllers.LogoutProcess)
|
||||||
|
app.Get("/welcome", controllers.WelcomePage)
|
||||||
|
app.Post("/welcome", controllers.WelcomePage)
|
||||||
app.Get("/mfa/totp/enroll", controllers.TotpEnrollPage)
|
app.Get("/mfa/totp/enroll", controllers.TotpEnrollPage)
|
||||||
|
|
||||||
listenAddr := fmt.Sprintf(
|
listenAddr := fmt.Sprintf(
|
||||||
|
|
|
||||||
59
middlewares/welcome.go
Normal file
59
middlewares/welcome.go
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
package middlewares
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.readonly.ch/bouzoure/popvaud-people/helpers"
|
||||||
|
"git.readonly.ch/bouzoure/popvaud-people/models"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WelcomeMiddleware(c *fiber.Ctx) error {
|
||||||
|
if c.Path() == "/login" || c.Path() == "/welcome" {
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := helpers.GetDatabase()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
userid, err := helpers.GetSessionUserId(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
result := db.First(&user, "id = ?", userid)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.SkipWelcome {
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Path() == "/" {
|
||||||
|
return c.Redirect("/welcome")
|
||||||
|
}
|
||||||
|
|
||||||
|
id := uuid.NewString()
|
||||||
|
key := fmt.Sprintf("redirect-%s", id)
|
||||||
|
|
||||||
|
sess, err := helpers.GetSessionStore(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sess.Set(key, c.Path())
|
||||||
|
sess.Save()
|
||||||
|
|
||||||
|
redirectUrl := fmt.Sprintf(
|
||||||
|
"/welcome?redirect=%s",
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
|
||||||
|
return c.Redirect(redirectUrl)
|
||||||
|
}
|
||||||
|
|
@ -14,4 +14,5 @@ type User struct {
|
||||||
TotpSercet sql.NullString
|
TotpSercet sql.NullString
|
||||||
DisabledAt sql.NullTime
|
DisabledAt sql.NullTime
|
||||||
IsAdmin bool
|
IsAdmin bool
|
||||||
|
SkipWelcome bool
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
views/welcome.pug
Normal file
30
views/welcome.pug
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
include partials/header.pug
|
||||||
|
|
||||||
|
.container
|
||||||
|
#login-card.my-5
|
||||||
|
.card
|
||||||
|
.card-header
|
||||||
|
| Paramètres du compte
|
||||||
|
.card-body
|
||||||
|
.alert.alert-danger
|
||||||
|
| !{.FormErrors}
|
||||||
|
form#login(method="post")
|
||||||
|
.mb-3
|
||||||
|
label.form-label(for="email") Adresse email
|
||||||
|
if .EmailUpdate
|
||||||
|
input#email.form-control(type="email", required, name="email", value=.Email)
|
||||||
|
else
|
||||||
|
input#email.form-control(type="text", disabled, name="email", value=.Email)
|
||||||
|
.mb-3
|
||||||
|
label.form-label(for="name") Nom complet
|
||||||
|
input#name.form-control(type="text", required, name="name", value=.Name)
|
||||||
|
.mb-3
|
||||||
|
label.form-label(for="password") Nouveau mot de passe
|
||||||
|
input#password.form-control(type="password", required, name="password")
|
||||||
|
.mb-3
|
||||||
|
label.form-label(for="password-verify") Vérifier le mot de passe
|
||||||
|
input#password-verify.form-control(type="password", required, name="password-verify")
|
||||||
|
.mt-3.text-end
|
||||||
|
button.btn.btn-primary(type="submit")
|
||||||
|
i.me-2(data-feather="save")
|
||||||
|
| Enregistrer
|
||||||
Loading…
Add table
Add a link
Reference in a new issue