Skip to content
Snippets Groups Projects
settings.go 3.88 KiB
package settings

import (
	"fmt"

	"github.com/gofiber/fiber/v2"
	"github.com/jmoiron/sqlx"
	"github.com/oidc-mytoken/api/v0"

	"github.com/oidc-mytoken/server/internal/config"
	"github.com/oidc-mytoken/server/internal/db"
	my "github.com/oidc-mytoken/server/internal/endpoints/token/mytoken/pkg"
	serverModel "github.com/oidc-mytoken/server/internal/model"
	"github.com/oidc-mytoken/server/internal/server/routes"
	"github.com/oidc-mytoken/server/internal/utils/auth"
	"github.com/oidc-mytoken/server/internal/utils/cookies"
	"github.com/oidc-mytoken/server/internal/utils/ctxUtils"
	"github.com/oidc-mytoken/server/internal/utils/errorfmt"
	"github.com/oidc-mytoken/server/internal/utils/logger"
	eventService "github.com/oidc-mytoken/server/shared/mytoken/event"
	event "github.com/oidc-mytoken/server/shared/mytoken/event/pkg"
	mytoken "github.com/oidc-mytoken/server/shared/mytoken/pkg"
	"github.com/oidc-mytoken/server/shared/mytoken/rotation"
	"github.com/oidc-mytoken/server/shared/mytoken/universalmytoken"
	"github.com/oidc-mytoken/server/shared/utils"
)

// InitSettings initializes the settings metadata
func InitSettings() {
	apiPaths := routes.GetCurrentAPIPaths()
	settingsMetadata.GrantTypeEndpoint = utils.CombineURLPath(
		config.Get().IssuerURL, apiPaths.UserSettingEndpoint, "grants",
	)
}

var settingsMetadata = api.SettingsMetaData{
	GrantTypeEndpoint: "grants",
}

func HandleSettings(ctx *fiber.Ctx) error {
	res := serverModel.Response{
		Status:   fiber.StatusOK,
		Response: settingsMetadata,
	}
	return res.Send(ctx)
}

// HandleSettingsHelper is a helper wrapper function that handles various settings request with the help of a callback
func HandleSettingsHelper(
	ctx *fiber.Ctx,
	reqMytoken *universalmytoken.UniversalMytoken,
	requiredCapability api.Capability,
	logEvent *event.Event,
	okStatus int,
	callback func(tx *sqlx.Tx, mt *mytoken.Mytoken) (my.TokenUpdatableResponse, *serverModel.Response),
	tokenGoneAfterCallback bool,
) error {
	rlog := logger.GetRequestLogger(ctx)
	mt, errRes := auth.RequireValidMytoken(rlog, nil, reqMytoken, ctx)
	if errRes != nil {
		return errRes.Send(ctx)
	}
	usedRestriction, errRes := auth.CheckCapabilityAndRestriction(
		rlog, nil, mt, ctx.IP(), nil, nil, requiredCapability,
	)
	if errRes != nil {
		return errRes.Send(ctx)
	}
	var tokenUpdate *my.MytokenResponse
	var rsp my.TokenUpdatableResponse
	if err := db.Transact(
		rlog, func(tx *sqlx.Tx) (err error) {
			rsp, errRes = callback(tx, mt)
			if errRes != nil {
				return fmt.Errorf("dummy")
			}
			if tokenGoneAfterCallback {
				return
			}
			clientMetaData := ctxUtils.ClientMetaData(ctx)
			if logEvent != nil {
				if err = eventService.LogEvent(
					rlog, tx, eventService.MTEvent{
						Event: logEvent,
						MTID:  mt.ID,
					}, *clientMetaData,
				); err != nil {
					return
				}
			}
			if usedRestriction != nil {
				if err = usedRestriction.UsedOther(rlog, tx, mt.ID); err != nil {
					return
				}
			}
			tokenUpdate, err = rotation.RotateMytokenAfterOtherForResponse(
				rlog, tx, reqMytoken.JWT, mt, *clientMetaData, reqMytoken.OriginalTokenType,
			)
			return
		},
	); err != nil {
		if errRes != nil {
			return errRes.Send(ctx)
		}
		rlog.Errorf("%s", errorfmt.Full(err))
		return serverModel.ErrorToInternalServerErrorResponse(err).Send(ctx)
	}

	var cake []*fiber.Cookie
	if tokenUpdate != nil {
		if rsp == nil {
			rsp = &onlyTokenUpdateRes{}
		}
		rsp.SetTokenUpdate(tokenUpdate)
		cake = []*fiber.Cookie{cookies.MytokenCookie(tokenUpdate.Mytoken)}
		okStatus = fiber.StatusOK
	}
	return serverModel.Response{
		Status:   okStatus,
		Response: rsp,
		Cookies:  cake,
	}.Send(ctx)
}

type onlyTokenUpdateRes struct {
	api.OnlyTokenUpdateResponse
	TokenUpdate *my.MytokenResponse `json:"token_update,omitempty"`
}

// SetTokenUpdate implements the pkg.TokenUpdatableResponse interface
func (res *onlyTokenUpdateRes) SetTokenUpdate(tokenUpdate *my.MytokenResponse) {
	res.TokenUpdate = tokenUpdate
}