Files
Maxence MaireauxandGitHub 22ebbe0a85 feat: CE/EE split architecture (#644)
* feat: Create EE architecture

* feat: Move Fireblocks to EE

* feat: Add dual CE/EE licensing model

Update root LICENSE to dual-license format distinguishing Community
Edition (MIT) from Enterprise Edition (ee/LICENSE), aligned with
the formancehq/stack licensing model.

* refactor: Rename main_ee.go to ee.go for cleaner build tag convention

* feat: Move Coinbase Prime to EE

* feat: just

* fix: tidy & package name
2026-02-24 15:26:29 +00:00

103 lines
2.6 KiB
Go

package fireblocks
import (
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"github.com/formancehq/payments/internal/connectors/plugins/sharedconfig"
"github.com/formancehq/payments/internal/models"
errorsutils "github.com/formancehq/payments/internal/utils/errors"
"github.com/go-playground/validator/v10"
"github.com/pkg/errors"
)
type Config struct {
APIKey string `json:"apiKey" validate:"required"`
PrivateKey string `json:"privateKey" validate:"required"`
Endpoint string `json:"endpoint"`
PollingPeriod sharedconfig.PollingPeriod `json:"pollingPeriod"`
privateKey *rsa.PrivateKey `json:"-"`
}
const (
PAGE_SIZE = 200
DefaultEndpoint = "https://api.fireblocks.io"
)
func (c *Config) validate() error {
p, _ := pem.Decode([]byte(c.PrivateKey))
if p == nil {
return errorsutils.NewWrappedError(
fmt.Errorf("invalid private key PEM in config"),
models.ErrInvalidConfig,
)
}
privateKey, err := x509.ParsePKCS1PrivateKey(p.Bytes)
if err != nil {
// Try PKCS8 format
key, err2 := x509.ParsePKCS8PrivateKey(p.Bytes)
if err2 != nil {
return errorsutils.NewWrappedError(
fmt.Errorf("failed to parse private key as PKCS1 (%w) or PKCS8 (%v)", err, err2),
models.ErrInvalidConfig,
)
}
rsaKey, ok := key.(*rsa.PrivateKey)
if !ok {
return errorsutils.NewWrappedError(
fmt.Errorf("private key is not RSA"),
models.ErrInvalidConfig,
)
}
privateKey = rsaKey
}
c.privateKey = privateKey
if c.Endpoint == "" {
c.Endpoint = DefaultEndpoint
}
return nil
}
func unmarshalAndValidateConfig(payload json.RawMessage) (Config, error) {
var raw struct {
APIKey string `json:"apiKey"`
PrivateKey string `json:"privateKey"`
Endpoint string `json:"endpoint"`
PollingPeriod string `json:"pollingPeriod"`
}
if err := json.Unmarshal(payload, &raw); err != nil {
return Config{}, errors.Wrap(models.ErrInvalidConfig, err.Error())
}
pp, err := sharedconfig.NewPollingPeriod(
raw.PollingPeriod,
sharedconfig.DefaultPollingPeriod,
sharedconfig.MinimumPollingPeriod,
)
if err != nil {
return Config{}, errors.Wrap(models.ErrInvalidConfig, err.Error())
}
config := Config{
APIKey: raw.APIKey,
PrivateKey: raw.PrivateKey,
Endpoint: raw.Endpoint,
PollingPeriod: pp,
}
validate := validator.New(validator.WithRequiredStructEnabled())
if err := validate.Struct(config); err != nil {
return config, errors.Wrap(models.ErrInvalidConfig, err.Error())
}
return config, config.validate()
}