143 lines
3.9 KiB
Go
143 lines
3.9 KiB
Go
package callbacksimp
|
|
|
|
import (
|
|
"context"
|
|
|
|
api "github.com/tech/sendico/pkg/api/http"
|
|
"github.com/tech/sendico/pkg/db/callbacks"
|
|
"github.com/tech/sendico/pkg/db/transaction"
|
|
"github.com/tech/sendico/pkg/merrors"
|
|
"github.com/tech/sendico/pkg/model"
|
|
"github.com/tech/sendico/pkg/mservice"
|
|
eapi "github.com/tech/sendico/server/interface/api"
|
|
"github.com/tech/sendico/server/internal/server/papitemplate"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type CallbacksAPI struct {
|
|
papitemplate.ProtectedAPI[model.Callback]
|
|
db callbacks.DB
|
|
tf transaction.Factory
|
|
secrets signingSecretManager
|
|
config callbacksConfig
|
|
}
|
|
|
|
func (a *CallbacksAPI) Name() mservice.Type {
|
|
return mservice.Callbacks
|
|
}
|
|
|
|
func (a *CallbacksAPI) Finish(_ context.Context) error {
|
|
return nil
|
|
}
|
|
|
|
func CreateAPI(apiCtx eapi.API) (*CallbacksAPI, error) {
|
|
dbFactory := func() (papitemplate.ProtectedDB[model.Callback], error) {
|
|
return apiCtx.DBFactory().NewCallbacksDB()
|
|
}
|
|
|
|
res := &CallbacksAPI{
|
|
config: newCallbacksConfig(apiCtx.Config().Callbacks),
|
|
tf: apiCtx.DBFactory().TransactionFactory(),
|
|
}
|
|
|
|
p, err := papitemplate.CreateAPI(apiCtx, dbFactory, mservice.Organizations, mservice.Callbacks)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
res.ProtectedAPI = *p.
|
|
WithNoCreateNotification().
|
|
WithNoUpdateNotification().
|
|
WithNoDeleteNotification().
|
|
WithCreateHandler(res.create).
|
|
WithUpdateHandler(res.update).
|
|
Build()
|
|
|
|
if res.db, err = apiCtx.DBFactory().NewCallbacksDB(); err != nil {
|
|
res.Logger.Warn("Failed to create callbacks database", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
if res.secrets, err = newSigningSecretManager(res.Logger, res.config); err != nil {
|
|
res.Logger.Warn("Failed to initialize callbacks signing secret manager", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
apiCtx.Register().AccountHandler(res.Name(), res.Cph.AddRef("/rotate-secret"), api.Post, res.rotateSecret)
|
|
|
|
return res, nil
|
|
}
|
|
|
|
const (
|
|
defaultCallbackStatus = model.CallbackStatusActive
|
|
defaultRetryMaxAttempts = 8
|
|
defaultRetryMinDelayMS = 1000
|
|
defaultRetryMaxDelayMS = 300000
|
|
defaultRetryRequestTimeoutMS = 10000
|
|
defaultSigningSecretLengthBytes = 32
|
|
defaultSigningSecretField = "value"
|
|
defaultSigningSecretPathPrefix = "sendico/callbacks"
|
|
)
|
|
|
|
type callbacksConfig struct {
|
|
DefaultEventTypes []string
|
|
DefaultStatus model.CallbackStatus
|
|
SecretPathPrefix string
|
|
SecretField string
|
|
SecretLengthBytes int
|
|
Vault VaultConfig
|
|
}
|
|
|
|
type VaultConfig struct {
|
|
Address string
|
|
TokenEnv string
|
|
TokenFileEnv string
|
|
TokenFile string
|
|
Namespace string
|
|
MountPath string
|
|
}
|
|
|
|
func newCallbacksConfig(source *eapi.CallbacksConfig) callbacksConfig {
|
|
cfg := callbacksConfig{
|
|
DefaultEventTypes: []string{model.PaymentStatusUpdatedType},
|
|
DefaultStatus: defaultCallbackStatus,
|
|
SecretPathPrefix: defaultSigningSecretPathPrefix,
|
|
SecretField: defaultSigningSecretField,
|
|
SecretLengthBytes: defaultSigningSecretLengthBytes,
|
|
}
|
|
if source == nil {
|
|
return cfg
|
|
}
|
|
|
|
if source.SecretPathPrefix != "" {
|
|
cfg.SecretPathPrefix = source.SecretPathPrefix
|
|
}
|
|
if source.SecretField != "" {
|
|
cfg.SecretField = source.SecretField
|
|
}
|
|
if source.SecretLengthBytes > 0 {
|
|
cfg.SecretLengthBytes = source.SecretLengthBytes
|
|
}
|
|
if len(source.DefaultEventTypes) > 0 {
|
|
cfg.DefaultEventTypes = source.DefaultEventTypes
|
|
}
|
|
if source.DefaultStatus != "" {
|
|
cfg.DefaultStatus = model.CallbackStatus(source.DefaultStatus)
|
|
}
|
|
cfg.Vault = VaultConfig{
|
|
Address: source.Vault.Address,
|
|
TokenEnv: source.Vault.TokenEnv,
|
|
TokenFileEnv: source.Vault.TokenFileEnv,
|
|
TokenFile: source.Vault.TokenFile,
|
|
Namespace: source.Vault.Namespace,
|
|
MountPath: source.Vault.MountPath,
|
|
}
|
|
return cfg
|
|
}
|
|
|
|
func (c callbacksConfig) validate() error {
|
|
if c.SecretLengthBytes <= 0 {
|
|
return merrors.InvalidArgument("callbacks signing secret length must be greater than zero", "api.callbacks.secret_length_bytes")
|
|
}
|
|
return nil
|
|
}
|