List, create & delete auth factor apis

This commit is contained in:
LittleSheep 2025-01-27 19:19:31 +08:00
parent a43e89a5a3
commit dc2de65245
6 changed files with 172 additions and 59 deletions

View File

@ -16,6 +16,8 @@ type AuthFactorType = int8
const (
PasswordAuthFactor = AuthFactorType(iota)
EmailPasswordFactor
InAppNotifyFactor
TimeOtpFactor
)
type AuthFactor struct {

View File

@ -83,39 +83,7 @@ func getUserinfo(c *fiber.Ctx) error {
return c.JSON(resp)
}
func getEvents(c *fiber.Ctx) error {
if err := exts.EnsureAuthenticated(c); err != nil {
return err
}
user := c.Locals("user").(models.Account)
take := c.QueryInt("take", 0)
offset := c.QueryInt("offset", 0)
var count int64
var events []models.ActionEvent
if err := database.C.
Where(&models.ActionEvent{AccountID: user.ID}).
Model(&models.ActionEvent{}).
Count(&count).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
if err := database.C.
Order("created_at desc").
Where(&models.ActionEvent{AccountID: user.ID}).
Limit(take).
Offset(offset).
Find(&events).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.JSON(fiber.Map{
"count": count,
"data": events,
})
}
func editUserinfo(c *fiber.Ctx) error {
func updateUserinfo(c *fiber.Ctx) error {
if err := exts.EnsureAuthenticated(c); err != nil {
return err
}

View File

@ -0,0 +1,40 @@
package api
import (
"git.solsynth.dev/hypernet/passport/pkg/authkit/models"
"git.solsynth.dev/hypernet/passport/pkg/internal/database"
"git.solsynth.dev/hypernet/passport/pkg/internal/http/exts"
"github.com/gofiber/fiber/v2"
)
func getEvents(c *fiber.Ctx) error {
if err := exts.EnsureAuthenticated(c); err != nil {
return err
}
user := c.Locals("user").(models.Account)
take := c.QueryInt("take", 0)
offset := c.QueryInt("offset", 0)
var count int64
var events []models.ActionEvent
if err := database.C.
Where(&models.ActionEvent{AccountID: user.ID}).
Model(&models.ActionEvent{}).
Count(&count).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
if err := database.C.
Order("created_at desc").
Where(&models.ActionEvent{AccountID: user.ID}).
Limit(take).
Offset(offset).
Find(&events).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.JSON(fiber.Map{
"count": count,
"data": events,
})
}

View File

@ -2,9 +2,13 @@ package api
import (
"fmt"
"git.solsynth.dev/hypernet/passport/pkg/authkit/models"
"git.solsynth.dev/hypernet/passport/pkg/internal/database"
"git.solsynth.dev/hypernet/passport/pkg/internal/http/exts"
"git.solsynth.dev/hypernet/passport/pkg/internal/services"
"github.com/gofiber/fiber/v2"
"github.com/samber/lo"
)
func getAvailableFactors(c *fiber.Ctx) error {
@ -42,42 +46,87 @@ func requestFactorToken(c *fiber.Ctx) error {
}
}
func requestResetPassword(c *fiber.Ctx) error {
func listFactor(c *fiber.Ctx) error {
if err := exts.EnsureAuthenticated(c); err != nil {
return err
}
user := c.Locals("user").(models.Account)
var factors []models.AuthFactor
if err := database.C.Where("account_id = ?", user.ID).Find(&factors).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.JSON(factors)
}
func createFactor(c *fiber.Ctx) error {
if err := exts.EnsureAuthenticated(c); err != nil {
return err
}
user := c.Locals("user").(models.Account)
var data struct {
UserID uint `json:"user_id" validate:"required"`
Type models.AuthFactorType `json:"type"`
Secret string `json:"secret"`
}
if err := exts.BindAndValidate(c, &data); err != nil {
return err
}
user, err := services.GetAccount(data.UserID)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
typeWhitelist := []models.AuthFactorType{
models.EmailPasswordFactor,
models.InAppNotifyFactor,
models.TimeOtpFactor,
}
if !lo.Contains(typeWhitelist, data.Type) {
return fiber.NewError(fiber.StatusBadRequest, "invalid factor type")
}
if err = services.CheckAbleToResetPassword(user); err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
} else if err = services.RequestResetPassword(user); err != nil {
// Currently, each type of factor can only be created once
var currentCount int64
if err := database.C.Model(&models.AuthFactor{}).
Where("account_id = ? AND type = ?", user.ID, data.Type).
Count(&currentCount).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("unable to check current factor count: %v", err))
} else if currentCount > 0 {
return fiber.NewError(fiber.StatusBadRequest, "this type of factor already exists")
}
factor := models.AuthFactor{
Type: data.Type,
Secret: data.Secret,
Account: user,
AccountID: user.ID,
}
if err := database.C.Create(&factor).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.JSON(factor)
}
func deleteFactor(c *fiber.Ctx) error {
id, _ := c.ParamsInt("factorId", 0)
if err := exts.EnsureAuthenticated(c); err != nil {
return err
}
user := c.Locals("user").(models.Account)
var factor models.AuthFactor
if err := database.C.Where("id = ? AND account_id = ?", id, user.ID).First(&factor).Error; err != nil {
return fiber.NewError(fiber.StatusNotFound, err.Error())
}
if factor.Type == models.PasswordAuthFactor {
return fiber.NewError(fiber.StatusBadRequest, "unable to delete password factor")
}
if err := database.C.Delete(&factor).Error; err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.SendStatus(fiber.StatusOK)
}
func confirmResetPassword(c *fiber.Ctx) error {
var data struct {
Code string `json:"code" validate:"required"`
NewPassword string `json:"new_password" validate:"required"`
}
if err := exts.BindAndValidate(c, &data); err != nil {
return err
}
if err := services.ConfirmResetPassword(data.Code, data.NewPassword); err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
return c.SendStatus(fiber.StatusOK)
}

View File

@ -60,7 +60,7 @@ func MapAPIs(app *fiber.App, baseURL string) {
me.Put("/banner", setBanner)
me.Get("/", getUserinfo)
me.Put("/", editUserinfo)
me.Put("/", updateUserinfo)
me.Get("/events", getEvents)
me.Get("/tickets", getTickets)
me.Delete("/tickets/:ticketId", killTicket)
@ -72,6 +72,13 @@ func MapAPIs(app *fiber.App, baseURL string) {
me.Put("/status", editStatus)
me.Delete("/status", clearStatus)
factors := me.Group("/factors").Name("Factors")
{
factors.Get("/", listFactor)
factors.Post("/", createFactor)
factors.Delete("/:factorId", deleteFactor)
}
relations := me.Group("/relations").Name("Relations")
{
relations.Post("/", makeFriendship)

View File

@ -0,0 +1,47 @@
package api
import (
"git.solsynth.dev/hypernet/passport/pkg/internal/http/exts"
"git.solsynth.dev/hypernet/passport/pkg/internal/services"
"github.com/gofiber/fiber/v2"
)
func requestResetPassword(c *fiber.Ctx) error {
var data struct {
UserID uint `json:"user_id" validate:"required"`
}
if err := exts.BindAndValidate(c, &data); err != nil {
return err
}
user, err := services.GetAccount(data.UserID)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
if err = services.CheckAbleToResetPassword(user); err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
} else if err = services.RequestResetPassword(user); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return c.SendStatus(fiber.StatusOK)
}
func confirmResetPassword(c *fiber.Ctx) error {
var data struct {
Code string `json:"code" validate:"required"`
NewPassword string `json:"new_password" validate:"required"`
}
if err := exts.BindAndValidate(c, &data); err != nil {
return err
}
if err := services.ConfirmResetPassword(data.Code, data.NewPassword); err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
return c.SendStatus(fiber.StatusOK)
}