117 lines
3.1 KiB
Go
117 lines
3.1 KiB
Go
|
package server
|
||
|
|
||
|
import (
|
||
|
"time"
|
||
|
|
||
|
"code.smartsheep.studio/hydrogen/bus/pkg/kit/adaptor"
|
||
|
"code.smartsheep.studio/hydrogen/bus/pkg/kit/publisher"
|
||
|
"code.smartsheep.studio/hydrogen/bus/pkg/wire"
|
||
|
"code.smartsheep.studio/hydrogen/passport/pkg/security"
|
||
|
"code.smartsheep.studio/hydrogen/passport/pkg/services"
|
||
|
"github.com/samber/lo"
|
||
|
)
|
||
|
|
||
|
func startChallenge(c *publisher.RequestCtx) error {
|
||
|
meta := adaptor.ParseAnyToStruct[wire.ClientMetadata](c.Metadata)
|
||
|
data := adaptor.ParseAnyToStruct[struct {
|
||
|
ID string `json:"id"`
|
||
|
}](c.Parameters)
|
||
|
|
||
|
user, err := services.LookupAccount(data.ID)
|
||
|
if err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
}
|
||
|
factors, err := services.LookupFactorsByUser(user.ID)
|
||
|
if err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
}
|
||
|
|
||
|
challenge, err := security.NewChallenge(user, factors, meta.ClientIp, meta.UserAgent)
|
||
|
if err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
}
|
||
|
|
||
|
return c.SendResponse(map[string]any{
|
||
|
"display_name": user.Nick,
|
||
|
"challenge": challenge,
|
||
|
"factors": factors,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func doChallenge(c *publisher.RequestCtx) error {
|
||
|
meta := adaptor.ParseAnyToStruct[wire.ClientMetadata](c.Metadata)
|
||
|
data := adaptor.ParseAnyToStruct[struct {
|
||
|
ChallengeID uint `json:"challenge_id"`
|
||
|
FactorID uint `json:"factor_id"`
|
||
|
Secret string `json:"secret"`
|
||
|
}](c.Parameters)
|
||
|
|
||
|
challenge, err := services.LookupChallengeWithFingerprint(data.ChallengeID, meta.ClientIp, meta.UserAgent)
|
||
|
if err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
}
|
||
|
|
||
|
factor, err := services.LookupFactor(data.FactorID)
|
||
|
if err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
}
|
||
|
|
||
|
if err := security.DoChallenge(challenge, factor, data.Secret); err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
}
|
||
|
|
||
|
challenge, err = services.LookupChallenge(data.ChallengeID)
|
||
|
if err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
} else if challenge.Progress >= challenge.Requirements {
|
||
|
session, err := security.GrantSession(challenge, []string{"*"}, nil, lo.ToPtr(time.Now()))
|
||
|
if err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
}
|
||
|
|
||
|
return c.SendResponse(map[string]any{
|
||
|
"is_finished": true,
|
||
|
"challenge": challenge,
|
||
|
"session": session,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
return c.SendResponse(map[string]any{
|
||
|
"is_finished": false,
|
||
|
"challenge": challenge,
|
||
|
"session": nil,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func exchangeToken(c *publisher.RequestCtx) error {
|
||
|
data := adaptor.ParseAnyToStruct[struct {
|
||
|
GrantToken string `json:"token"`
|
||
|
}](c.Parameters)
|
||
|
|
||
|
access, refresh, err := security.ExchangeToken(data.GrantToken)
|
||
|
if err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
}
|
||
|
|
||
|
return c.SendResponse(map[string]any{
|
||
|
"access_token": access,
|
||
|
"refresh_token": refresh,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func refreshToken(c *publisher.RequestCtx) error {
|
||
|
data := adaptor.ParseAnyToStruct[struct {
|
||
|
RefreshToken string `json:"token"`
|
||
|
}](c.Parameters)
|
||
|
|
||
|
access, refresh, err := security.RefreshToken(data.RefreshToken)
|
||
|
if err != nil {
|
||
|
return c.SendError(wire.InvalidActions, err)
|
||
|
}
|
||
|
|
||
|
return c.SendResponse(map[string]any{
|
||
|
"access_token": access,
|
||
|
"refresh_token": refresh,
|
||
|
})
|
||
|
}
|