mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-04 18:31:41 +00:00
@@ -0,0 +1,295 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user