mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-03 09:51:39 +00:00
296 lines
8.9 KiB
Go
296 lines
8.9 KiB
Go
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
|
|
}
|
|
}
|