🎨 Update project structure
This commit is contained in:
51
pkg/internal/server/ui/accounts.go
Normal file
51
pkg/internal/server/ui/accounts.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"time"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gomarkdown/markdown"
|
||||
"github.com/gomarkdown/markdown/html"
|
||||
"github.com/gomarkdown/markdown/parser"
|
||||
"github.com/sujit-baniya/flash"
|
||||
)
|
||||
|
||||
func selfUserinfoPage(c *fiber.Ctx) error {
|
||||
user := c.Locals("principal").(models.Account)
|
||||
|
||||
var data models.Account
|
||||
if err := database.C.
|
||||
Where(&models.Account{BaseModel: models.BaseModel{ID: user.ID}}).
|
||||
Preload("Profile").
|
||||
Preload("PersonalPage").
|
||||
Preload("Contacts").
|
||||
First(&data).Error; err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
birthday := "Unknown"
|
||||
if data.Profile.Birthday != nil {
|
||||
birthday = data.Profile.Birthday.Format(time.RFC822)
|
||||
}
|
||||
|
||||
doc := parser.
|
||||
NewWithExtensions(parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock).
|
||||
Parse([]byte(data.PersonalPage.Content))
|
||||
|
||||
renderer := html.NewRenderer(html.RendererOptions{Flags: html.CommonFlags | html.HrefTargetBlank})
|
||||
|
||||
return c.Render("views/users/me", fiber.Map{
|
||||
"info": flash.Get(c)["message"],
|
||||
"uid": fmt.Sprintf("%08d", data.ID),
|
||||
"joined_at": data.CreatedAt.Format(time.RFC822),
|
||||
"birthday_at": birthday,
|
||||
"personal_page": template.HTML(markdown.Render(doc, renderer)),
|
||||
"userinfo": data,
|
||||
"avatar": data.GetAvatar(),
|
||||
"banner": data.GetBanner(),
|
||||
}, "views/layouts/user-center")
|
||||
}
|
47
pkg/internal/server/ui/index.go
Normal file
47
pkg/internal/server/ui/index.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/utils"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func MapUserInterface(A *fiber.App, authFunc utils.AuthFunc) {
|
||||
authCheckWare := func(c *fiber.Ctx) error {
|
||||
var token string
|
||||
if cookie := c.Cookies(services.CookieAccessKey); len(cookie) > 0 {
|
||||
token = cookie
|
||||
}
|
||||
|
||||
c.Locals("token", token)
|
||||
|
||||
if err := authFunc(c); err != nil {
|
||||
uri := c.Request().URI().FullURI()
|
||||
return c.Redirect(fmt.Sprintf("/sign-in?redirect_uri=%s", string(uri)))
|
||||
} else {
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
pages := A.Group("/").Name("Pages")
|
||||
|
||||
pages.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.Redirect("/users/me")
|
||||
})
|
||||
|
||||
pages.Get("/sign-up", signupPage)
|
||||
pages.Get("/sign-in", signinPage)
|
||||
pages.Get("/mfa", mfaRequestPage)
|
||||
pages.Get("/mfa/apply", mfaApplyPage)
|
||||
pages.Get("/authorize", authCheckWare, authorizePage)
|
||||
|
||||
pages.Post("/sign-up", signupAction)
|
||||
pages.Post("/sign-in", signinAction)
|
||||
pages.Post("/mfa", mfaRequestAction)
|
||||
pages.Post("/mfa/apply", mfaApplyAction)
|
||||
pages.Post("/authorize", authCheckWare, authorizeAction)
|
||||
|
||||
pages.Get("/users/me", authCheckWare, selfUserinfoPage)
|
||||
}
|
194
pkg/internal/server/ui/mfa.go
Normal file
194
pkg/internal/server/ui/mfa.go
Normal file
@@ -0,0 +1,194 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/utils"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sujit-baniya/flash"
|
||||
)
|
||||
|
||||
func mfaRequestPage(c *fiber.Ctx) error {
|
||||
ticketId := c.QueryInt("ticket", 0)
|
||||
|
||||
ticket, err := services.GetTicket(uint(ticketId))
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": "you must provide ticket id to perform multi-factor authenticate",
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
user, err := services.GetAccount(ticket.AccountID)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": "ticket related user just weirdly disappear",
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
factors, err := services.ListUserFactor(user.ID)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("unable to get your factors: %v", err.Error()),
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
|
||||
factors = lo.Filter(factors, func(item models.AuthFactor, index int) bool {
|
||||
return item.Type != models.PasswordAuthFactor
|
||||
})
|
||||
|
||||
localizer := c.Locals("localizer").(*i18n.Localizer)
|
||||
|
||||
next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"})
|
||||
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaTitle"})
|
||||
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaCaption"})
|
||||
|
||||
return c.Render("views/mfa", fiber.Map{
|
||||
"info": flash.Get(c)["message"],
|
||||
"redirect_uri": flash.Get(c)["redirect_uri"],
|
||||
"ticket_id": ticket.ID,
|
||||
"factors": lo.Map(factors, func(item models.AuthFactor, index int) fiber.Map {
|
||||
return fiber.Map{
|
||||
"name": services.GetFactorName(item.Type, localizer),
|
||||
"id": item.ID,
|
||||
}
|
||||
}),
|
||||
"i18n": fiber.Map{
|
||||
"next": next,
|
||||
"title": title,
|
||||
"caption": caption,
|
||||
},
|
||||
}, "views/layouts/auth")
|
||||
}
|
||||
|
||||
func mfaRequestAction(c *fiber.Ctx) error {
|
||||
var data struct {
|
||||
TicketID uint `form:"ticket_id" validate:"required"`
|
||||
FactorID uint `form:"factor_id" validate:"required"`
|
||||
}
|
||||
|
||||
redirectBackUri := "/sign-in"
|
||||
err := utils.BindAndValidate(c, &data)
|
||||
|
||||
if data.TicketID > 0 {
|
||||
redirectBackUri = fmt.Sprintf("/mfa?ticket=%d", data.TicketID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": err.Error(),
|
||||
}).Redirect(redirectBackUri)
|
||||
}
|
||||
|
||||
factor, err := services.GetFactor(data.FactorID)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("factor was not found: %v", err.Error()),
|
||||
}).Redirect(redirectBackUri)
|
||||
}
|
||||
|
||||
_, err = services.GetFactorCode(factor)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("unable to get factor code: %v", err.Error()),
|
||||
}).Redirect(redirectBackUri)
|
||||
}
|
||||
|
||||
return flash.WithData(c, fiber.Map{
|
||||
"redirect_uri": utils.GetRedirectUri(c),
|
||||
}).Redirect(fmt.Sprintf("/mfa/apply?ticket=%d&factor=%d", data.TicketID, factor.ID))
|
||||
}
|
||||
|
||||
func mfaApplyPage(c *fiber.Ctx) error {
|
||||
ticketId := c.QueryInt("ticket", 0)
|
||||
factorId := c.QueryInt("factor", 0)
|
||||
|
||||
ticket, err := services.GetTicket(uint(ticketId))
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("unable to find your ticket: %v", err.Error()),
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
factor, err := services.GetFactor(uint(factorId))
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("unable to find your factors: %v", err.Error()),
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
|
||||
localizer := c.Locals("localizer").(*i18n.Localizer)
|
||||
|
||||
next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"})
|
||||
password, _ := localizer.LocalizeMessage(&i18n.Message{ID: "password"})
|
||||
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaTitle"})
|
||||
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "mfaCaption"})
|
||||
|
||||
return c.Render("views/mfa-apply", fiber.Map{
|
||||
"info": flash.Get(c)["message"],
|
||||
"label": services.GetFactorName(factor.Type, localizer),
|
||||
"ticket_id": ticket.ID,
|
||||
"factor_id": factor.ID,
|
||||
"i18n": fiber.Map{
|
||||
"next": next,
|
||||
"password": password,
|
||||
"title": title,
|
||||
"caption": caption,
|
||||
},
|
||||
}, "views/layouts/auth")
|
||||
}
|
||||
|
||||
func mfaApplyAction(c *fiber.Ctx) error {
|
||||
var data struct {
|
||||
TicketID uint `form:"ticket_id" validate:"required"`
|
||||
FactorID uint `form:"factor_id" validate:"required"`
|
||||
Code string `form:"code" validate:"required"`
|
||||
}
|
||||
|
||||
redirectBackUri := "/sign-in"
|
||||
err := utils.BindAndValidate(c, &data)
|
||||
|
||||
if data.TicketID > 0 {
|
||||
redirectBackUri = fmt.Sprintf("/mfa/apply?ticket=%d&factor=%d", data.TicketID, data.FactorID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": err.Error(),
|
||||
}).Redirect(redirectBackUri)
|
||||
}
|
||||
|
||||
ticket, err := services.GetTicket(data.TicketID)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("unable to find your ticket: %v", err.Error()),
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
factor, err := services.GetFactor(data.FactorID)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("factor was not found: %v", err.Error()),
|
||||
}).Redirect(redirectBackUri)
|
||||
}
|
||||
|
||||
ticket, err = services.ActiveTicketWithMFA(ticket, factor, data.Code)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("invalid multi-factor authenticate code: %v", err.Error()),
|
||||
}).Redirect(redirectBackUri)
|
||||
} else if ticket.IsAvailable() != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": "ticket weirdly still unavailable after multi-factor authenticate",
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
|
||||
access, refresh, err := services.ExchangeToken(*ticket.GrantToken)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("failed to exchange token: %v", err.Error()),
|
||||
}).Redirect("/sign-in")
|
||||
} else {
|
||||
services.SetJwtCookieSet(c, access, refresh)
|
||||
}
|
||||
|
||||
return c.Redirect(lo.FromPtr(utils.GetRedirectUri(c, "/users/me")))
|
||||
}
|
154
pkg/internal/server/ui/oauth.go
Normal file
154
pkg/internal/server/ui/oauth.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sujit-baniya/flash"
|
||||
"html/template"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func authorizePage(c *fiber.Ctx) error {
|
||||
localizer := c.Locals("localizer").(*i18n.Localizer)
|
||||
user := c.Locals("principal").(models.Account)
|
||||
|
||||
id := c.Query("client_id")
|
||||
redirect := c.Query("redirect_uri")
|
||||
|
||||
var message string
|
||||
if len(id) <= 0 || len(redirect) <= 0 {
|
||||
message = "invalid request, missing query parameters"
|
||||
}
|
||||
|
||||
var client models.ThirdClient
|
||||
if err := database.C.Where(&models.ThirdClient{Alias: id}).First(&client).Error; err != nil {
|
||||
message = fmt.Sprintf("unable to find client: %v", err)
|
||||
} else if !client.IsDraft && !lo.Contains(client.Callbacks, strings.Split(redirect, "?")[0]) {
|
||||
message = "invalid callback url"
|
||||
}
|
||||
|
||||
var ticket models.AuthTicket
|
||||
if err := database.C.Where(&models.AuthTicket{
|
||||
AccountID: user.ID,
|
||||
ClientID: &client.ID,
|
||||
}).Where("last_grant_at IS NULL").First(&ticket).Error; err == nil {
|
||||
if !(ticket.ExpiredAt != nil && ticket.ExpiredAt.Unix() < time.Now().Unix()) {
|
||||
ticket, err = services.RegenSession(ticket)
|
||||
if c.Query("response_type") == "code" {
|
||||
return c.Redirect(fmt.Sprintf(
|
||||
"%s?code=%s&state=%s",
|
||||
redirect,
|
||||
*ticket.GrantToken,
|
||||
c.Query("state"),
|
||||
))
|
||||
} else if c.Query("response_type") == "token" {
|
||||
if access, refresh, err := services.GetToken(ticket); err == nil {
|
||||
return c.Redirect(fmt.Sprintf("%s?access_token=%s&refresh_token=%s&state=%s",
|
||||
redirect,
|
||||
access,
|
||||
refresh, c.Query("state"),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decline, _ := localizer.LocalizeMessage(&i18n.Message{ID: "decline"})
|
||||
approve, _ := localizer.LocalizeMessage(&i18n.Message{ID: "approve"})
|
||||
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "authorizeTitle"})
|
||||
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "authorizeCaption"})
|
||||
|
||||
qs := "/authorize?" + string(c.Request().URI().QueryString())
|
||||
|
||||
return c.Render("views/authorize", fiber.Map{
|
||||
"info": lo.Ternary[any](len(message) > 0, message, flash.Get(c)["message"]),
|
||||
"client": client,
|
||||
"scopes": strings.Split(c.Query("scope"), " "),
|
||||
"action_url": template.URL(qs),
|
||||
"i18n": fiber.Map{
|
||||
"approve": approve,
|
||||
"decline": decline,
|
||||
"title": title,
|
||||
"caption": caption,
|
||||
},
|
||||
}, "views/layouts/auth")
|
||||
}
|
||||
|
||||
func authorizeAction(c *fiber.Ctx) error {
|
||||
user := c.Locals("principal").(models.Account)
|
||||
id := c.Query("client_id")
|
||||
response := c.Query("response_type")
|
||||
redirect := c.Query("redirect_uri")
|
||||
scope := c.Query("scope")
|
||||
|
||||
redirectBackUri := "/authorize?" + string(c.Request().URI().QueryString())
|
||||
|
||||
if len(scope) <= 0 {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": "invalid request parameters",
|
||||
}).Redirect(redirectBackUri)
|
||||
}
|
||||
|
||||
var client models.ThirdClient
|
||||
if err := database.C.Where(&models.ThirdClient{Alias: id}).First(&client).Error; err != nil {
|
||||
return fiber.NewError(fiber.StatusNotFound, err.Error())
|
||||
}
|
||||
|
||||
switch response {
|
||||
case "code":
|
||||
// OAuth Authorization Mode
|
||||
ticket, err := services.NewOauthTicket(
|
||||
user,
|
||||
client,
|
||||
strings.Split(scope, " "),
|
||||
[]string{"passport", client.Alias},
|
||||
c.IP(),
|
||||
c.Get(fiber.HeaderUserAgent),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
} else {
|
||||
services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent))
|
||||
return c.Redirect(fmt.Sprintf(
|
||||
"%s?code=%s&state=%s",
|
||||
redirect,
|
||||
*ticket.GrantToken,
|
||||
c.Query("state"),
|
||||
))
|
||||
}
|
||||
case "token":
|
||||
// OAuth Implicit Mode
|
||||
ticket, err := services.NewOauthTicket(
|
||||
user,
|
||||
client,
|
||||
strings.Split(scope, " "),
|
||||
[]string{"passport", client.Alias},
|
||||
c.IP(),
|
||||
c.Get(fiber.HeaderUserAgent),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
} else if access, refresh, err := services.GetToken(ticket); err != nil {
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
} else {
|
||||
services.AddEvent(user, "oauth.connect", client.Alias, c.IP(), c.Get(fiber.HeaderUserAgent))
|
||||
return c.Redirect(fmt.Sprintf("%s?access_token=%s&refresh_token=%s&state=%s",
|
||||
redirect,
|
||||
access,
|
||||
refresh, c.Query("state"),
|
||||
))
|
||||
}
|
||||
default:
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": "unsupported response type",
|
||||
}).Redirect(redirectBackUri)
|
||||
}
|
||||
}
|
93
pkg/internal/server/ui/signin.go
Normal file
93
pkg/internal/server/ui/signin.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/utils"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sujit-baniya/flash"
|
||||
)
|
||||
|
||||
func signinPage(c *fiber.Ctx) error {
|
||||
localizer := c.Locals("localizer").(*i18n.Localizer)
|
||||
|
||||
next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"})
|
||||
username, _ := localizer.LocalizeMessage(&i18n.Message{ID: "username"})
|
||||
password, _ := localizer.LocalizeMessage(&i18n.Message{ID: "password"})
|
||||
signup, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signupTitle"})
|
||||
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinTitle"})
|
||||
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinCaption"})
|
||||
requiredNotify, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinRequired"})
|
||||
|
||||
var info any
|
||||
if flash.Get(c)["message"] != nil {
|
||||
info = flash.Get(c)["message"]
|
||||
} else {
|
||||
info = requiredNotify
|
||||
}
|
||||
|
||||
return c.Render("views/signin", fiber.Map{
|
||||
"info": info,
|
||||
"i18n": fiber.Map{
|
||||
"next": next,
|
||||
"username": username,
|
||||
"password": password,
|
||||
"signup": signup,
|
||||
"title": title,
|
||||
"caption": caption,
|
||||
},
|
||||
}, "views/layouts/auth")
|
||||
}
|
||||
|
||||
func signinAction(c *fiber.Ctx) error {
|
||||
var data struct {
|
||||
Username string `form:"username" validate:"required"`
|
||||
Password string `form:"password" validate:"required"`
|
||||
}
|
||||
|
||||
if err := utils.BindAndValidate(c, &data); err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": err.Error(),
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
|
||||
user, err := services.LookupAccount(data.Username)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("account was not found: %v", err.Error()),
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
|
||||
ticket, err := services.NewTicket(user, c.IP(), c.Get(fiber.HeaderUserAgent))
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("unable setup ticket: %v", err.Error()),
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
|
||||
ticket, err = services.ActiveTicketWithPassword(ticket, data.Password)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("invalid password: %v", err.Error()),
|
||||
}).Redirect("/sign-in")
|
||||
}
|
||||
|
||||
if ticket.IsAvailable() != nil {
|
||||
return flash.WithData(c, fiber.Map{
|
||||
"redirect_uri": utils.GetRedirectUri(c),
|
||||
}).Redirect(fmt.Sprintf("/mfa?ticket=%d", ticket.ID))
|
||||
}
|
||||
|
||||
access, refresh, err := services.ExchangeToken(*ticket.GrantToken)
|
||||
if err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("failed to exchange token: %v", err.Error()),
|
||||
}).Redirect("/sign-in")
|
||||
} else {
|
||||
services.SetJwtCookieSet(c, access, refresh)
|
||||
}
|
||||
|
||||
return c.Redirect(lo.FromPtr(utils.GetRedirectUri(c, "/users/me")))
|
||||
}
|
87
pkg/internal/server/ui/signup.go
Normal file
87
pkg/internal/server/ui/signup.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/models"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/services"
|
||||
"git.solsynth.dev/hydrogen/passport/pkg/utils"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/sujit-baniya/flash"
|
||||
)
|
||||
|
||||
func signupPage(c *fiber.Ctx) error {
|
||||
localizer := c.Locals("localizer").(*i18n.Localizer)
|
||||
|
||||
next, _ := localizer.LocalizeMessage(&i18n.Message{ID: "next"})
|
||||
email, _ := localizer.LocalizeMessage(&i18n.Message{ID: "email"})
|
||||
nickname, _ := localizer.LocalizeMessage(&i18n.Message{ID: "nickname"})
|
||||
username, _ := localizer.LocalizeMessage(&i18n.Message{ID: "username"})
|
||||
password, _ := localizer.LocalizeMessage(&i18n.Message{ID: "password"})
|
||||
magicToken, _ := localizer.LocalizeMessage(&i18n.Message{ID: "magicToken"})
|
||||
signin, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signinTitle"})
|
||||
title, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signupTitle"})
|
||||
caption, _ := localizer.LocalizeMessage(&i18n.Message{ID: "signupCaption"})
|
||||
|
||||
return c.Render("views/signup", fiber.Map{
|
||||
"info": flash.Get(c)["message"],
|
||||
"use_magic_token": viper.GetBool("use_registration_magic_token"),
|
||||
"i18n": fiber.Map{
|
||||
"next": next,
|
||||
"email": email,
|
||||
"username": username,
|
||||
"nickname": nickname,
|
||||
"password": password,
|
||||
"magic_token": magicToken,
|
||||
"signin": signin,
|
||||
"title": title,
|
||||
"caption": caption,
|
||||
},
|
||||
}, "views/layouts/auth")
|
||||
}
|
||||
|
||||
func signupAction(c *fiber.Ctx) error {
|
||||
var data struct {
|
||||
Name string `form:"name" validate:"required,lowercase,alphanum,min=4,max=16"`
|
||||
Nick string `form:"nick" validate:"required,min=4,max=24"`
|
||||
Email string `form:"email" validate:"required,email"`
|
||||
Password string `form:"password" validate:"required,min=4,max=32"`
|
||||
MagicToken string `form:"magic_token"`
|
||||
}
|
||||
|
||||
if err := utils.BindAndValidate(c, &data); err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": err.Error(),
|
||||
}).Redirect("/sign-up")
|
||||
} else if viper.GetBool("use_registration_magic_token") && len(data.MagicToken) <= 0 {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": "magic token was required",
|
||||
}).Redirect("/sign-up")
|
||||
} else if viper.GetBool("use_registration_magic_token") {
|
||||
if tk, err := services.ValidateMagicToken(data.MagicToken, models.RegistrationMagicToken); err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": fmt.Sprintf("magic token was invalid: %v", err.Error()),
|
||||
}).Redirect("/sign-up")
|
||||
} else {
|
||||
database.C.Delete(&tk)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := services.CreateAccount(
|
||||
data.Name,
|
||||
data.Nick,
|
||||
data.Email,
|
||||
data.Password,
|
||||
); err != nil {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": err.Error(),
|
||||
}).Redirect("/sign-up")
|
||||
} else {
|
||||
return flash.WithInfo(c, fiber.Map{
|
||||
"message": "account has been created. now you can sign in!",
|
||||
}).Redirect(lo.FromPtr(utils.GetRedirectUri(c, "/sign-in")))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user