otp

package
v0.0.0-...-1fb332c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 24, 2026 License: Apache-2.0 Imports: 27 Imported by: 1

Documentation

Index

Constants

View Source
const (
	WhatsappCodeDuration = duration.UserInteraction
)

Variables

View Source
var ErrCodeNotFound = InvalidOTPCode.NewWithCause("otp code is expired or invalid", apierrors.StringCause("CodeNotFound"))
View Source
var ErrConsumedCode = InvalidOTPCode.NewWithCause("used otp code", apierrors.StringCause("UsedCode"))
View Source
var ErrInvalidCode = InvalidOTPCode.NewWithCause("invalid otp code", apierrors.StringCause("InvalidCode"))
View Source
var ErrOTPDeliveryUnexpectedError = apierrors.InternalError.
	WithReason("OTPDeliveryUnexpectedError").
	New("unexpected error occurs on sending the message")
View Source
var ErrTooManyAttempts = ratelimit.RateLimited.NewWithInfo("too many verify OTP attempts", apierrors.Details{
	"bucket_name": "TrackFailedOTPAttemptBucket",
})

FIXME: backward compat; should not use RateLimited

View Source
var FromAdminAPIQueryKey = "x_from_admin_api"
View Source
var InvalidOTPCode = apierrors.Forbidden.WithReason("InvalidOTPCode")
View Source
var SenderLogger = slogutil.NewLogger("otp-sender")
View Source
var ServiceLogger = slogutil.NewLogger("otp")
View Source
var UtilsLogger = slogutil.NewLogger("otp-utils")

Functions

This section is empty.

Types

type AdditionalContext

type AdditionalContext struct {
	HasPassword bool
}

type AttemptTracker

type AttemptTracker interface {
	ResetFailedAttempts(ctx context.Context, kind Kind, target string) error
	GetFailedAttempts(ctx context.Context, kind Kind, target string) (int, error)
	IncrementFailedAttempts(ctx context.Context, kind Kind, target string) (int, error)
}

type AttemptTrackerRedis

type AttemptTrackerRedis struct {
	Redis *appredis.Handle
	AppID config.AppID
	Clock clock.Clock
}

func (*AttemptTrackerRedis) GetFailedAttempts

func (s *AttemptTrackerRedis) GetFailedAttempts(ctx context.Context, kind Kind, target string) (int, error)

func (*AttemptTrackerRedis) IncrementFailedAttempts

func (s *AttemptTrackerRedis) IncrementFailedAttempts(ctx context.Context, kind Kind, target string) (int, error)

func (*AttemptTrackerRedis) ResetFailedAttempts

func (s *AttemptTrackerRedis) ResetFailedAttempts(ctx context.Context, kind Kind, target string) error

type Code

type Code struct {
	Target   string    `json:"target"`
	Purpose  Purpose   `json:"purpose"`
	Form     Form      `json:"form"`
	Code     string    `json:"code"`
	ExpireAt time.Time `json:"expire_at"`
	Consumed bool      `json:"consumed"`

	UserInputtedCode string `json:"user_inputted_code,omitempty"`
	UserID           string `json:"user_id,omitempty"`

	// For interaction
	WebSessionID string `json:"web_session_id,omitempty"`

	// For legacy workflow
	WorkflowID string `json:"workflow_id,omitempty"`

	// For authentication flow
	AuthenticationFlowWebsocketChannelName string        `json:"authentication_flow_websocket_channel_name,omitempty"`
	AuthenticationFlowType                 string        `json:"authentication_flow_type,omitempty"`
	AuthenticationFlowName                 string        `json:"authentication_flow_name,omitempty"`
	AuthenticationFlowJSONPointer          jsonpointer.T `json:"authentication_flow_json_pointer,omitempty"`

	// The message which carries the otp
	OOBChannel        model.AuthenticatorOOBChannel `json:"channel,omitzero"`
	WhatsappMessageID string                        `json:"whatsapp_message_id,omitzero"`
	SendMessageError  *apierrors.APIError           `json:"send_message_error"`
}

type CodeStore

type CodeStore interface {
	Create(ctx context.Context, purpose Purpose, code *Code) error
	Get(ctx context.Context, purpose Purpose, target string) (*Code, error)
	Update(ctx context.Context, purpose Purpose, code *Code) error
	Delete(ctx context.Context, purpose Purpose, target string) error
}

type CodeStoreRedis

type CodeStoreRedis struct {
	Redis *appredis.Handle
	AppID config.AppID
	Clock clock.Clock
}

func (*CodeStoreRedis) Create

func (s *CodeStoreRedis) Create(ctx context.Context, purpose Purpose, code *Code) error

func (*CodeStoreRedis) Delete

func (s *CodeStoreRedis) Delete(ctx context.Context, purpose Purpose, target string) error

func (*CodeStoreRedis) Get

func (s *CodeStoreRedis) Get(ctx context.Context, purpose Purpose, target string) (*Code, error)

func (*CodeStoreRedis) Update

func (s *CodeStoreRedis) Update(ctx context.Context, purpose Purpose, code *Code) error

type DeprecatedKindFactory

type DeprecatedKindFactory func(config *config.AppConfig, channel model.AuthenticatorOOBChannel) Kind

type EndpointsProvider

type EndpointsProvider interface {
	Origin() *neturl.URL
	LoginLinkVerificationEndpointURL() *neturl.URL
	ResetPasswordEndpointURL() *neturl.URL
}

type Form

type Form string
const (
	FormCode Form = "code"
	FormLink Form = "link"
)

func (Form) AllowLookupByCode

func (f Form) AllowLookupByCode() bool

func (Form) CodeLength

func (f Form) CodeLength() int

func (Form) GenerateCode

func (f Form) GenerateCode(cfg *config.TestModeConfig, featureCfg *config.TestModeFeatureConfig, target string, userID string) string

func (Form) VerifyCode

func (f Form) VerifyCode(input string, expected string) bool

type FraudProtectionService

type FraudProtectionService interface {
	RecordSMSOTPVerified(ctx context.Context, phoneNumber string) error
}

type GenerateOptions

type GenerateOptions struct {
	UserID                                 string
	WebSessionID                           string
	WorkflowID                             string
	AuthenticationFlowWebsocketChannelName string
	AuthenticationFlowType                 string
	AuthenticationFlowName                 string
	AuthenticationFlowJSONPointer          jsonpointer.T
	SkipRateLimits                         bool
}

type Kind

type Kind interface {
	Purpose() Purpose
	ValidPeriod() time.Duration

	RateLimitTrigger(
		featureConfig *config.FeatureConfig,
		envConfig *config.RateLimitsEnvironmentConfig,
		ip string, userID string,
	) []*ratelimit.BucketSpec
	RateLimitValidate(
		featureConfig *config.FeatureConfig,
		envConfig *config.RateLimitsEnvironmentConfig,
		ip string, userID string,
	) []*ratelimit.BucketSpec

	RateLimitTriggerCooldown(target string) ratelimit.BucketSpec
	RevocationMaxFailedAttempts() int
}
func KindForgotPasswordLink(
	config *config.AppConfig,
	channel model.AuthenticatorOOBChannel) Kind

func KindForgotPasswordOTP

func KindForgotPasswordOTP(
	config *config.AppConfig,
	channel model.AuthenticatorOOBChannel) Kind

func KindOOBOTPCode

func KindOOBOTPCode(config *config.AppConfig, channel model.AuthenticatorOOBChannel) Kind
func KindOOBOTPLink(config *config.AppConfig, channel model.AuthenticatorOOBChannel) Kind

func KindOOBOTPWithForm

func KindOOBOTPWithForm(config *config.AppConfig, channel model.AuthenticatorOOBChannel, form Form) Kind

func KindVerification

func KindVerification(config *config.AppConfig, channel model.AuthenticatorOOBChannel) Kind

type LookupStore

type LookupStore interface {
	Create(ctx context.Context, purpose Purpose, code string, target string, expireAt time.Time) error
	Get(ctx context.Context, purpose Purpose, code string) (string, error)
	Delete(ctx context.Context, purpose Purpose, code string) error
}

type LookupStoreRedis

type LookupStoreRedis struct {
	Redis *appredis.Handle
	AppID config.AppID
	Clock clock.Clock
}

func (*LookupStoreRedis) Create

func (s *LookupStoreRedis) Create(ctx context.Context, purpose Purpose, code string, target string, expireAt time.Time) error

func (*LookupStoreRedis) Delete

func (s *LookupStoreRedis) Delete(ctx context.Context, purpose Purpose, code string) error

func (*LookupStoreRedis) Get

func (s *LookupStoreRedis) Get(ctx context.Context, purpose Purpose, code string) (target string, err error)

type MessageSender

type MessageSender struct {
	AppID       config.AppID
	Translation TranslationService
	Endpoints   EndpointsProvider
	Sender      Sender
	CodeStore   SenderCodeStore

	WhatsappConfig *config.WhatsappConfig
}

func (*MessageSender) Send

func (s *MessageSender) Send(ctx context.Context, opts SendOptions) error

func (*MessageSender) SendAsync

func (s *MessageSender) SendAsync(ctx context.Context, opts SendOptions) error

type OTPDeliveryStatusInternal

type OTPDeliveryStatusInternal string
const (
	OTPDeliveryStatusInternalPending OTPDeliveryStatusInternal = "pending"
	OTPDeliveryStatusInternalSending OTPDeliveryStatusInternal = "sending"
	OTPDeliveryStatusInternalFailed  OTPDeliveryStatusInternal = "failed"
	OTPDeliveryStatusInternalSent    OTPDeliveryStatusInternal = "sent"
)

func (OTPDeliveryStatusInternal) ToAPIStatus

type Purpose

type Purpose string
const PurposeForgotPassword Purpose = "forgot-password"
const PurposeOOBOTP Purpose = "oob-otp"
const PurposeVerification Purpose = "verification"

type SendOptions

type SendOptions struct {
	Channel                 model.AuthenticatorOOBChannel
	Target                  string
	Form                    Form
	Type                    translation.MessageType
	Kind                    Kind
	OTP                     string
	AdditionalContext       *AdditionalContext
	IsAdminAPIResetPassword bool
}

type Sender

type Sender interface {
	SendEmailInNewGoroutine(ctx context.Context, msgType translation.MessageType, opts *mail.SendOptions) error
	SendSMSImmediately(ctx context.Context, msgType translation.MessageType, opts *sms.SendOptions) error
	SendSMSInNewGoroutine(ctx context.Context, msgType translation.MessageType, opts *sms.SendOptions) error
	SendWhatsappInNewGoroutine(ctx context.Context, msgType translation.MessageType, opts *whatsapp.SendAuthenticationOTPOptions, resultCallback messaging.SendWhatsappResultCallback, errCalllback messaging.SendWhatsappErrorCallback) error
}

type SenderCodeStore

type SenderCodeStore interface {
	Get(ctx context.Context, purpose Purpose, target string) (*Code, error)
	Update(ctx context.Context, purpose Purpose, code *Code) error
}

type Service

type Service struct {
	Clock clock.Clock

	AppID                 config.AppID
	TestModeConfig        *config.TestModeConfig
	TestModeFeatureConfig *config.TestModeFeatureConfig
	RemoteIP              httputil.RemoteIP
	CodeStore             CodeStore
	LookupStore           LookupStore
	AttemptTracker        AttemptTracker
	RateLimiter           RateLimiter
	WhatsappService       WhatsappService
	FraudProtection       FraudProtectionService

	FeatureConfig *config.FeatureConfig
	EnvConfig     *config.RateLimitsEnvironmentConfig
}

func (*Service) ConsumeCode

func (s *Service) ConsumeCode(ctx context.Context, purpose Purpose, target string) error

func (*Service) GenerateOTP

func (s *Service) GenerateOTP(ctx context.Context, kind Kind, target string, form Form, opts *GenerateOptions) (string, error)

func (*Service) InspectCode

func (s *Service) InspectCode(ctx context.Context, purpose Purpose, target string) (*Code, error)

func (*Service) InspectState

func (s *Service) InspectState(ctx context.Context, kind Kind, target string) (*State, error)

func (*Service) LookupCode

func (s *Service) LookupCode(ctx context.Context, purpose Purpose, code string) (target string, err error)

func (*Service) SetSubmittedCode

func (s *Service) SetSubmittedCode(ctx context.Context, kind Kind, target string, code string) (*State, error)

func (*Service) VerifyOTP

func (s *Service) VerifyOTP(ctx context.Context, kind Kind, target string, otp string, opts *VerifyOptions) error

type State

type State struct {
	Target                string
	CanResendAt           time.Time
	CanCheckSubmittedCode bool
	UserID                string
	TooManyAttempts       bool

	WebSessionID                           string
	WorkflowID                             string
	AuthenticationFlowWebsocketChannelName string
	AuthenticationFlowType                 string
	AuthenticationFlowName                 string
	AuthenticationFlowJSONPointer          jsonpointer.T

	DeliveryStatus model.OTPDeliveryStatus
	DeliveryError  *apierrors.APIError
}

type VerifyOptions

type VerifyOptions struct {
	UserID           string
	UseSubmittedCode bool
	SkipConsume      bool
}

type WhatsappService

type WhatsappService interface {
	GetMessageStatus(ctx context.Context, messageID string) (*whatsapp.GetMessageStatusResult, error)
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL