125 lines
3.0 KiB
Go
125 lines
3.0 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/99designs/gqlgen/graphql"
|
|
"github.com/google/uuid"
|
|
"github.com/lestrrat-go/jwx/jwt"
|
|
|
|
"reichard.io/imagini/graph/model"
|
|
)
|
|
|
|
func (api *API) refreshTokens(refreshToken jwt.Token) (string, string, error) {
|
|
// Acquire User & Device
|
|
did, ok := refreshToken.Get("did")
|
|
if !ok {
|
|
return "", "", errors.New("Missing DID")
|
|
}
|
|
uid, ok := refreshToken.Get(jwt.SubjectKey)
|
|
if !ok {
|
|
return "", "", errors.New("Missing UID")
|
|
}
|
|
deviceUUID, err := uuid.Parse(fmt.Sprintf("%v", did))
|
|
if err != nil {
|
|
return "", "", errors.New("Invalid DID")
|
|
}
|
|
userUUID, err := uuid.Parse(fmt.Sprintf("%v", uid))
|
|
if err != nil {
|
|
return "", "", errors.New("Invalid UID")
|
|
}
|
|
|
|
// Device & User Skeleton
|
|
user := model.User{ID: userUUID.String()}
|
|
device := model.Device{ID: deviceUUID.String()}
|
|
|
|
// Find User
|
|
_, err = api.DB.User(&user)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
// Update Access Token
|
|
accessTokenCookie, err := api.Auth.CreateJWTAccessToken(user, device)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
return accessTokenCookie, "", err
|
|
}
|
|
|
|
func (api *API) validateTokens(w *http.ResponseWriter, r *http.Request) (jwt.Token, error) {
|
|
// Validate Access Token
|
|
accessCookie, _ := r.Cookie("AccessToken")
|
|
if accessCookie != nil {
|
|
accessToken, err := api.Auth.ValidateJWTAccessToken(accessCookie.Value)
|
|
if err == nil {
|
|
return accessToken, nil
|
|
}
|
|
}
|
|
|
|
// Validate Refresh Cookie Exists
|
|
refreshCookie, _ := r.Cookie("RefreshToken")
|
|
if refreshCookie == nil {
|
|
return nil, errors.New("Tokens Invalid")
|
|
}
|
|
|
|
// Validate Refresh Token
|
|
refreshToken, err := api.Auth.ValidateJWTRefreshToken(refreshCookie.Value)
|
|
if err != nil {
|
|
return nil, errors.New("Tokens Invalid")
|
|
}
|
|
|
|
// Refresh Access Token & Generate New Refresh Token
|
|
newAccessCookie, newRefreshCookie, err := api.refreshTokens(refreshToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// TODO: Actually Refresh Refresh Token
|
|
newRefreshCookie = refreshCookie.Value
|
|
|
|
// Update Access & Refresh Cookies
|
|
http.SetCookie(*w, &http.Cookie{
|
|
Name: "AccessToken",
|
|
Value: newAccessCookie,
|
|
})
|
|
http.SetCookie(*w, &http.Cookie{
|
|
Name: "RefreshToken",
|
|
Value: newRefreshCookie,
|
|
})
|
|
|
|
return jwt.ParseBytes([]byte(newAccessCookie))
|
|
}
|
|
|
|
func (api *API) hasMinRoleDirective(ctx context.Context, obj interface{}, next graphql.Resolver, role model.Role) (res interface{}, err error) {
|
|
authContext := ctx.Value("auth").(*model.AuthContext)
|
|
accessToken, err := api.validateTokens(authContext.AuthResponse, authContext.AuthRequest)
|
|
if err != nil {
|
|
return nil, errors.New("Access Denied")
|
|
}
|
|
authContext.AccessToken = &accessToken
|
|
|
|
userRole, ok := accessToken.Get("role")
|
|
if !ok {
|
|
return nil, errors.New("Access Denied")
|
|
}
|
|
|
|
if userRole == model.RoleAdmin.String() {
|
|
return next(ctx)
|
|
}
|
|
|
|
if userRole == role.String() {
|
|
return next(ctx)
|
|
}
|
|
|
|
return nil, errors.New("Role Not Authenticated")
|
|
}
|
|
|
|
func (api *API) metaDirective(ctx context.Context, obj interface{}, next graphql.Resolver, gorm *string) (res interface{}, err error) {
|
|
return next(ctx)
|
|
}
|