Files
sonr/x/dwn/client/plugin/config.go
T

296 lines
8.9 KiB
Go
Raw Normal View History

2025-10-03 14:45:52 -04:00
package plugin
import (
"encoding/json"
"fmt"
"time"
extism "github.com/extism/go-sdk"
"github.com/sonr-io/sonr/crypto/mpc"
)
// EnclaveConfig represents the MPC enclave configuration for the Motor plugin.
// This configuration is passed to the plugin via PDK environment variables.
type EnclaveConfig struct {
// ChainID specifies the blockchain network identifier (e.g., "sonr-testnet-1")
ChainID string `json:"chain_id" yaml:"chain_id"`
// EnclaveData contains the MPC enclave data with private key material
EnclaveData *mpc.EnclaveData `json:"enclave_data" yaml:"enclave_data"`
// VaultConfig provides additional vault configuration parameters
VaultConfig VaultConfig `json:"vault_config" yaml:"vault_config"`
// Security settings for plugin operations
Security SecurityConfig `json:"security" yaml:"security"`
// Timeout configurations for various operations
Timeouts TimeoutConfig `json:"timeouts" yaml:"timeouts"`
}
// VaultConfig specifies vault-specific configuration parameters.
type VaultConfig struct {
// IPFSEndpoint specifies the IPFS endpoint for vault operations
IPFSEndpoint string `json:"ipfs_endpoint" yaml:"ipfs_endpoint"`
// MaxVaultSize limits the maximum size of vault data in bytes
MaxVaultSize int64 `json:"max_vault_size" yaml:"max_vault_size"`
// EnableCompression enables compression for vault data
EnableCompression bool `json:"enable_compression" yaml:"enable_compression"`
// BackupEnabled enables automatic backup of vault data
BackupEnabled bool `json:"backup_enabled" yaml:"backup_enabled"`
// Custom metadata for vault operations
Metadata map[string]string `json:"metadata,omitempty" yaml:"metadata,omitempty"`
}
// SecurityConfig defines security parameters for plugin operations.
type SecurityConfig struct {
// RequiredAttestations specifies required security attestations
RequiredAttestations []string `json:"required_attestations" yaml:"required_attestations"`
// MaxTokenLifetime limits the maximum lifetime of generated tokens
MaxTokenLifetime time.Duration `json:"max_token_lifetime" yaml:"max_token_lifetime"`
// RequireAudience enforces audience validation for all tokens
RequireAudience bool `json:"require_audience" yaml:"require_audience"`
// AllowedOrigins specifies allowed origins for token delegation
AllowedOrigins []string `json:"allowed_origins" yaml:"allowed_origins"`
}
// TimeoutConfig specifies timeout values for various plugin operations.
type TimeoutConfig struct {
// TokenCreation timeout for UCAN token creation operations
TokenCreation time.Duration `json:"token_creation" yaml:"token_creation"`
// Signature timeout for cryptographic signing operations
Signature time.Duration `json:"signature" yaml:"signature"`
// Verification timeout for signature verification operations
Verification time.Duration `json:"verification" yaml:"verification"`
// PluginInit timeout for plugin initialization
PluginInit time.Duration `json:"plugin_init" yaml:"plugin_init"`
}
// DefaultEnclaveConfig returns a default enclave configuration with sensible defaults.
func DefaultEnclaveConfig() *EnclaveConfig {
return &EnclaveConfig{
ChainID: "sonr-testnet-1",
VaultConfig: VaultConfig{
IPFSEndpoint: "127.0.0.1:5001",
MaxVaultSize: 10 * 1024 * 1024, // 10MB
EnableCompression: true,
BackupEnabled: false,
Metadata: make(map[string]string),
},
Security: SecurityConfig{
RequiredAttestations: []string{},
MaxTokenLifetime: 24 * time.Hour,
RequireAudience: true,
AllowedOrigins: []string{"*"},
},
Timeouts: TimeoutConfig{
TokenCreation: 30 * time.Second,
Signature: 10 * time.Second,
Verification: 5 * time.Second,
PluginInit: 15 * time.Second,
},
}
}
// Validate checks that the enclave configuration is valid and complete.
func (c *EnclaveConfig) Validate() error {
if c.ChainID == "" {
return fmt.Errorf("chain_id is required")
}
if c.EnclaveData == nil {
return fmt.Errorf("enclave_data is required")
}
if !c.EnclaveData.IsValid() {
return fmt.Errorf("enclave_data is invalid")
}
// Validate vault configuration
if err := c.VaultConfig.Validate(); err != nil {
return fmt.Errorf("vault_config validation failed: %w", err)
}
// Validate security configuration
if err := c.Security.Validate(); err != nil {
return fmt.Errorf("security configuration validation failed: %w", err)
}
return nil
}
// ToManifestConfig converts the enclave configuration to Extism manifest config.
// This is used to pass configuration to the WASM plugin via environment variables.
func (c *EnclaveConfig) ToManifestConfig() (map[string]string, error) {
config := make(map[string]string)
// Add chain ID
config["chain_id"] = c.ChainID
// Serialize and add enclave data
if c.EnclaveData != nil {
enclaveBytes, err := json.Marshal(c.EnclaveData)
if err != nil {
return nil, fmt.Errorf("failed to marshal enclave data: %w", err)
}
config["enclave"] = string(enclaveBytes)
}
// Serialize and add vault configuration
vaultBytes, err := json.Marshal(c.VaultConfig)
if err != nil {
return nil, fmt.Errorf("failed to marshal vault config: %w", err)
}
config["vault_config"] = string(vaultBytes)
// Serialize and add security configuration
securityBytes, err := json.Marshal(c.Security)
if err != nil {
return nil, fmt.Errorf("failed to marshal security config: %w", err)
}
config["security_config"] = string(securityBytes)
// Serialize and add timeout configuration
timeoutBytes, err := json.Marshal(c.Timeouts)
if err != nil {
return nil, fmt.Errorf("failed to marshal timeout config: %w", err)
}
config["timeout_config"] = string(timeoutBytes)
return config, nil
}
// Validate checks that the vault configuration is valid.
func (v *VaultConfig) Validate() error {
if v.MaxVaultSize <= 0 {
return fmt.Errorf("max_vault_size must be positive")
}
if v.MaxVaultSize > 100*1024*1024 { // 100MB limit
return fmt.Errorf("max_vault_size exceeds maximum allowed (100MB)")
}
return nil
}
// Validate checks that the security configuration is valid.
func (s *SecurityConfig) Validate() error {
if s.MaxTokenLifetime <= 0 {
return fmt.Errorf("max_token_lifetime must be positive")
}
if s.MaxTokenLifetime > 30*24*time.Hour { // 30 days limit
return fmt.Errorf("max_token_lifetime exceeds maximum allowed (30 days)")
}
return nil
}
// LoaderConfig represents configuration for the plugin loader itself.
type LoaderConfig struct {
// EnableWASI enables WebAssembly System Interface for the plugin
EnableWASI bool
// MemoryLimit sets the maximum memory limit for the plugin in bytes
MemoryLimit uint32
// AllowHttpRequests enables HTTP requests from the plugin
AllowHttpRequests bool
// LogLevel sets the logging level for plugin operations
LogLevel string
// MaxConcurrentPlugins limits the number of concurrent plugin instances
MaxConcurrentPlugins int
}
// DefaultLoaderConfig returns a default loader configuration.
func DefaultLoaderConfig() *LoaderConfig {
return &LoaderConfig{
EnableWASI: true,
MemoryLimit: 64 * 1024 * 1024, // 64MB
AllowHttpRequests: false,
LogLevel: "info",
MaxConcurrentPlugins: 10,
}
}
// ToPluginConfig converts the loader configuration to Extism plugin config.
func (l *LoaderConfig) ToPluginConfig() extism.PluginConfig {
return extism.PluginConfig{
EnableWasi: l.EnableWASI,
}
}
// PluginState represents the runtime state of a plugin instance.
type PluginState struct {
// ID is the unique identifier for this plugin instance
ID string
// Config is the configuration used to create this plugin
Config *EnclaveConfig
// Plugin is the underlying Extism plugin instance
Plugin *extism.Plugin
// CreatedAt is the timestamp when the plugin was created
CreatedAt time.Time
// LastUsed is the timestamp of the last plugin operation
LastUsed time.Time
// IsHealthy indicates whether the plugin is in a healthy state
IsHealthy bool
// ErrorCount tracks the number of errors encountered
ErrorCount int
// MaxErrors is the maximum number of errors before marking unhealthy
MaxErrors int
}
// UpdateHealth updates the plugin health status based on operation result.
func (s *PluginState) UpdateHealth(err error) {
s.LastUsed = time.Now()
if err != nil {
s.ErrorCount++
if s.ErrorCount >= s.MaxErrors {
s.IsHealthy = false
}
} else {
// Reset error count on successful operation
s.ErrorCount = 0
s.IsHealthy = true
}
}
// IsExpired checks if the plugin instance should be considered expired.
func (s *PluginState) IsExpired(maxIdleTime time.Duration) bool {
return time.Since(s.LastUsed) > maxIdleTime
}
// NewPluginState creates a new plugin state with default values.
func NewPluginState(id string, config *EnclaveConfig, plugin *extism.Plugin) *PluginState {
return &PluginState{
ID: id,
Config: config,
Plugin: plugin,
CreatedAt: time.Now(),
LastUsed: time.Now(),
IsHealthy: true,
ErrorCount: 0,
MaxErrors: 5, // Allow up to 5 errors before marking as unhealthy
}
}