You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.7 KiB
147 lines
3.7 KiB
package httpapi
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"git.aiterp.net/stufflog3/stufflog3/entities"
|
|
"git.aiterp.net/stufflog3/stufflog3/models"
|
|
"git.aiterp.net/stufflog3/stufflog3/usecases/auth"
|
|
"github.com/gin-gonic/gin"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
type loginInput struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
RefreshToken string `json:"refreshToken"`
|
|
}
|
|
|
|
type setupInput struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
Session string `json:"session"`
|
|
}
|
|
|
|
func Auth(g *gin.RouterGroup, service *auth.Service) {
|
|
g.GET("", handler("user", func(c *gin.Context) (interface{}, error) {
|
|
token := c.GetHeader("Authorization")
|
|
if len(token) < 8 {
|
|
return nil, models.PermissionDeniedError{}
|
|
}
|
|
|
|
return service.Provider.ValidateToken(c.Request.Context(), token[7:]), nil
|
|
}))
|
|
|
|
g.POST("/login", handler("auth", func(c *gin.Context) (interface{}, error) {
|
|
input := &loginInput{}
|
|
err := c.BindJSON(input)
|
|
if err != nil {
|
|
return nil, models.BadInputError{
|
|
Object: "LoginInput",
|
|
Problem: "Invalid JSON: " + err.Error(),
|
|
}
|
|
}
|
|
|
|
return service.Provider.LoginUser(c.Request.Context(), input.Username, input.Password)
|
|
}))
|
|
|
|
g.POST("/refresh", handler("auth", func(c *gin.Context) (interface{}, error) {
|
|
input := &loginInput{}
|
|
err := c.BindJSON(input)
|
|
if err != nil {
|
|
return nil, models.BadInputError{
|
|
Object: "LoginInput",
|
|
Problem: "Invalid JSON: " + err.Error(),
|
|
}
|
|
}
|
|
|
|
token := c.GetHeader("Authorization")
|
|
if len(token) < 8 || input.RefreshToken == "" {
|
|
return nil, models.BadInputError{
|
|
Object: "LoginInput",
|
|
Problem: "Missing token(s)",
|
|
}
|
|
}
|
|
|
|
return service.Provider.RefreshUser(c.Request.Context(), token[7:], input.RefreshToken)
|
|
}))
|
|
|
|
g.POST("/setup", handler("auth", func(c *gin.Context) (interface{}, error) {
|
|
input := &setupInput{}
|
|
err := c.BindJSON(input)
|
|
if err != nil {
|
|
return nil, models.BadInputError{
|
|
Object: "LoginInput",
|
|
Problem: "Invalid JSON: " + err.Error(),
|
|
}
|
|
}
|
|
|
|
return service.Provider.SetupUser(c.Request.Context(), input.Session, input.Username, input.Password)
|
|
}))
|
|
}
|
|
|
|
func DummyMiddleware(auth *auth.Service, uuid string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
c.Request = c.Request.WithContext(
|
|
auth.ContextWithUser(c.Request.Context(), entities.User{ID: uuid}),
|
|
)
|
|
}
|
|
}
|
|
|
|
func abortRequest(c *gin.Context) {
|
|
c.AbortWithStatusJSON(http.StatusUnauthorized, Error{
|
|
Code: http.StatusUnauthorized,
|
|
Message: "You're not supposed to be here!",
|
|
})
|
|
}
|
|
|
|
// TrustingJwtParserMiddleware is meant to be put behind an AWS API gateway that has already
|
|
// verified this token.
|
|
func TrustingJwtParserMiddleware(auth *auth.Service) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
authHeader := c.GetHeader("Authorization")
|
|
split := strings.Split(authHeader, ".")
|
|
|
|
if len(split) >= 3 {
|
|
data, err := base64.RawStdEncoding.DecodeString(split[1])
|
|
if err != nil {
|
|
abortRequest(c)
|
|
return
|
|
}
|
|
|
|
fields := make(map[string]interface{})
|
|
err = json.Unmarshal(data, &fields)
|
|
if err != nil {
|
|
abortRequest(c)
|
|
return
|
|
}
|
|
|
|
if sub, ok := fields["sub"].(string); ok {
|
|
c.Request = c.Request.WithContext(
|
|
auth.ContextWithUser(c.Request.Context(), entities.User{ID: sub}),
|
|
)
|
|
} else {
|
|
abortRequest(c)
|
|
return
|
|
}
|
|
} else {
|
|
abortRequest(c)
|
|
}
|
|
}
|
|
}
|
|
|
|
// JwtValidatorMiddleware does check the JWT against the provider.
|
|
func JwtValidatorMiddleware(s *auth.Service) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
header := c.GetHeader("Authorization")
|
|
if header != "" {
|
|
user := s.ValidateUser(c.Request.Context(), header[7:])
|
|
if user != nil {
|
|
c.Request = c.Request.WithContext(
|
|
s.ContextWithUser(c.Request.Context(), *user),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|