Passport/pkg/server/challanges_api.go

141 lines
3.9 KiB
Go
Raw Normal View History

2024-01-26 17:11:32 +00:00
package server
import (
"time"
2024-03-20 12:56:43 +00:00
"github.com/gofiber/fiber/v2"
"git.solsynth.dev/hydrogen/identity/pkg/security"
"git.solsynth.dev/hydrogen/identity/pkg/services"
2024-01-26 17:11:32 +00:00
"github.com/samber/lo"
)
func startChallenge(c *fiber.Ctx) error {
var data struct {
2024-01-31 13:16:54 +00:00
ID string `json:"id" validate:"required"`
2024-01-26 17:11:32 +00:00
}
if err := BindAndValidate(c, &data); err != nil {
return err
}
user, err := services.LookupAccount(data.ID)
if err != nil {
return fiber.NewError(fiber.StatusNotFound, err.Error())
}
factors, err := services.LookupFactorsByUser(user.ID)
if err != nil {
return fiber.NewError(fiber.StatusNotFound, err.Error())
}
challenge, err := security.NewChallenge(user, factors, c.IP(), c.Get(fiber.HeaderUserAgent))
if err != nil {
return fiber.NewError(fiber.StatusNotFound, err.Error())
}
2024-01-30 09:57:23 +00:00
services.AddEvent(user, "challenges.start", data.ID, c.IP(), c.Get(fiber.HeaderUserAgent))
2024-01-26 17:11:32 +00:00
return c.JSON(fiber.Map{
"display_name": user.Nick,
"challenge": challenge,
"factors": factors,
})
}
func doChallenge(c *fiber.Ctx) error {
var data struct {
2024-01-31 13:16:54 +00:00
ChallengeID uint `json:"challenge_id" validate:"required"`
FactorID uint `json:"factor_id" validate:"required"`
Secret string `json:"secret" validate:"required"`
2024-01-26 17:11:32 +00:00
}
if err := BindAndValidate(c, &data); err != nil {
return err
}
challenge, err := services.LookupChallengeWithFingerprint(data.ChallengeID, c.IP(), c.Get(fiber.HeaderUserAgent))
if err != nil {
return fiber.NewError(fiber.StatusNotFound, err.Error())
}
factor, err := services.LookupFactor(data.FactorID)
if err != nil {
return fiber.NewError(fiber.StatusNotFound, err.Error())
}
if err := security.DoChallenge(challenge, factor, data.Secret); err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
challenge, err = services.LookupChallenge(data.ChallengeID)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
} else if challenge.Progress >= challenge.Requirements {
2024-02-18 03:20:22 +00:00
session, err := security.GrantSession(challenge, []string{"*"}, []string{"identity"}, nil, lo.ToPtr(time.Now()))
2024-01-26 17:11:32 +00:00
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
return c.JSON(fiber.Map{
"is_finished": true,
"challenge": challenge,
"session": session,
})
}
return c.JSON(fiber.Map{
"is_finished": false,
"challenge": challenge,
"session": nil,
})
}
func exchangeToken(c *fiber.Ctx) error {
var data struct {
2024-01-30 07:57:49 +00:00
Code string `json:"code" form:"code"`
2024-01-30 09:57:23 +00:00
RefreshToken string `json:"refresh_token" form:"refresh_token"`
2024-01-30 07:57:49 +00:00
ClientID string `json:"client_id" form:"client_id"`
ClientSecret string `json:"client_secret" form:"client_secret"`
RedirectUri string `json:"redirect_uri" form:"redirect_uri"`
GrantType string `json:"grant_type" form:"grant_type"`
2024-01-26 17:11:32 +00:00
}
if err := BindAndValidate(c, &data); err != nil {
return err
}
var err error
var access, refresh string
2024-01-26 17:11:32 +00:00
switch data.GrantType {
case "authorization_code":
2024-01-30 07:57:49 +00:00
// Authorization Code Mode
access, refresh, err = security.ExchangeOauthToken(data.ClientID, data.ClientSecret, data.RedirectUri, data.Code)
2024-01-30 07:57:49 +00:00
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
case "grant_token":
// Internal Usage
access, refresh, err = security.ExchangeToken(data.Code)
2024-01-26 17:11:32 +00:00
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
case "refresh_token":
2024-01-30 07:57:49 +00:00
// Refresh Token
access, refresh, err = security.RefreshToken(data.RefreshToken)
2024-01-26 17:11:32 +00:00
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
default:
2024-01-30 07:57:49 +00:00
return fiber.NewError(fiber.StatusBadRequest, "unsupported exchange token type")
2024-01-26 17:11:32 +00:00
}
security.SetJwtCookieSet(c, access, refresh)
return c.JSON(fiber.Map{
"id_token": access,
"access_token": access,
"refresh_token": refresh,
"token_type": "Bearer",
"expires_in": (30 * time.Minute).Seconds(),
})
2024-01-26 17:11:32 +00:00
}