hydra/flow/flow_encoding.go

122 lines
3.7 KiB
Go

// Copyright © 2025 Ory Corp
// SPDX-License-Identifier: Apache-2.0
package flow
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/ory/hydra/v2/driver/config"
"github.com/ory/hydra/v2/fosite"
"github.com/ory/hydra/v2/x"
"github.com/ory/x/otelx"
)
type decodeDependencies interface {
CipherProvider
x.NetworkProvider
config.Provider
x.TracingProvider
}
func decodeFlow(ctx context.Context, d decodeDependencies, enc string, p purpose) (_ *Flow, err error) {
f, err := Decode[Flow](ctx, d.FlowCipher(), enc, withPurpose(p))
if err != nil {
return nil, errors.WithStack(x.ErrNotFound.WithWrap(err))
}
if f.NID != d.Networker().NetworkID(ctx) {
return nil, errors.WithStack(x.ErrNotFound.WithDescription("Network IDs are not matching."))
}
if f.RequestedAt.Add(d.Config().ConsentRequestMaxAge(ctx)).Before(time.Now()) {
return nil, errors.WithStack(fosite.ErrRequestUnauthorized.WithHintf("The %s request has expired, please try again.", p.RequestType()))
}
return f, nil
}
func DecodeFromLoginChallenge(ctx context.Context, d decodeDependencies, challenge string) (_ *Flow, err error) {
ctx, span := d.Tracer(ctx).Tracer().Start(ctx, "flow.DecodeFromLoginChallenge")
defer otelx.End(span, &err)
return decodeFlow(ctx, d, challenge, loginChallenge)
}
func DecodeFromConsentChallenge(ctx context.Context, d decodeDependencies, challenge string) (_ *Flow, err error) {
ctx, span := d.Tracer(ctx).Tracer().Start(ctx, "flow.DecodeFromConsentChallenge")
defer otelx.End(span, &err)
return decodeFlow(ctx, d, challenge, consentChallenge)
}
func DecodeFromDeviceChallenge(ctx context.Context, d decodeDependencies, challenge string) (_ *Flow, err error) {
ctx, span := d.Tracer(ctx).Tracer().Start(ctx, "flow.DecodeFromDeviceChallenge")
defer otelx.End(span, &err)
return decodeFlow(ctx, d, challenge, deviceChallenge)
}
func decodeVerifier(ctx context.Context, d decodeDependencies, verifier string, p purpose) (_ *Flow, err error) {
f, err := decodeFlow(ctx, d, verifier, p)
if err != nil {
if errors.Is(err, x.ErrNotFound) {
return nil, errors.WithStack(fosite.ErrAccessDenied.WithHintf("The %s verifier has already been used, has not been granted, or is invalid.", p.RequestType()))
}
return nil, err
}
return f, nil
}
func DecodeAndInvalidateLoginVerifier(ctx context.Context, d decodeDependencies, verifier string) (_ *Flow, err error) {
ctx, span := d.Tracer(ctx).Tracer().Start(ctx, "flow.DecodeAndInvalidateLoginVerifier")
defer otelx.End(span, &err)
f, err := decodeVerifier(ctx, d, verifier, loginVerifier)
if err != nil {
return nil, err
}
if err := f.InvalidateLoginRequest(); err != nil {
return nil, errors.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error()))
}
return f, nil
}
func DecodeAndInvalidateDeviceVerifier(ctx context.Context, d decodeDependencies, verifier string) (_ *Flow, err error) {
ctx, span := d.Tracer(ctx).Tracer().Start(ctx, "flow.DecodeAndInvalidateDeviceVerifier")
defer otelx.End(span, &err)
f, err := decodeVerifier(ctx, d, verifier, deviceVerifier)
if err != nil {
return nil, err
}
if err = f.InvalidateDeviceRequest(); err != nil {
return nil, errors.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error()))
}
return f, nil
}
func DecodeAndInvalidateConsentVerifier(ctx context.Context, d decodeDependencies, verifier string) (_ *Flow, err error) {
ctx, span := d.Tracer(ctx).Tracer().Start(ctx, "flow.DecodeAndInvalidateLoginVerifier")
defer otelx.End(span, &err)
f, err := decodeVerifier(ctx, d, verifier, consentVerifier)
if err != nil {
return nil, err
}
if err = f.InvalidateConsentRequest(); err != nil {
return nil, errors.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error()))
}
return f, nil
}