mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-05 02:41:41 +00:00
@@ -0,0 +1,190 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/asynkron/protoactor-go/actor"
|
||||
)
|
||||
|
||||
// Actor represents the UCAN actor that handles MPC-based cryptographic operations.
|
||||
// It maintains a WebAssembly plugin for secure UCAN token operations and
|
||||
// uses behavioral state management to handle different actor lifecycle phases.
|
||||
type Actor struct {
|
||||
ctx context.Context // Context for managing plugin lifecycle
|
||||
behavior actor.Behavior // Behavioral state manager for handling different phases
|
||||
enclave Plugin // MPC enclave plugin instance
|
||||
config *EnclaveConfig // Configuration for enclave initialization (optional)
|
||||
}
|
||||
|
||||
// NewActor creates a new UCAN actor instance.
|
||||
// The actor starts in an uninitialized state and transitions to initialized
|
||||
// once the MPC enclave plugin is successfully loaded.
|
||||
func NewActor() actor.Actor {
|
||||
return &Actor{
|
||||
ctx: context.Background(),
|
||||
behavior: actor.NewBehavior(),
|
||||
}
|
||||
}
|
||||
|
||||
// Props returns the actor properties configuration for creating new UCAN actors.
|
||||
// It uses NewActor as the producer function to create UCAN actor instances.
|
||||
func Props() *actor.Props {
|
||||
return actor.PropsFromProducer(NewActor)
|
||||
}
|
||||
|
||||
// PropsWithConfig returns actor properties configured with specific enclave data.
|
||||
// This allows creating actors with pre-configured enclave data for testing or specific use cases.
|
||||
func PropsWithConfig(config *EnclaveConfig) *actor.Props {
|
||||
return actor.PropsFromProducer(func() actor.Actor {
|
||||
return &Actor{
|
||||
ctx: context.Background(),
|
||||
behavior: actor.NewBehavior(),
|
||||
config: config, // Store config for initialization
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Receive is the main message handler for the UCAN actor.
|
||||
// It handles actor lifecycle messages and delegates other messages to the current behavior.
|
||||
// The actor uses behavioral patterns to handle different states (uninitialized vs initialized).
|
||||
func (a *Actor) Receive(c actor.Context) {
|
||||
switch c.Message().(type) {
|
||||
case *actor.Started:
|
||||
a.handleStarted(c)
|
||||
case *actor.Stopping:
|
||||
a.handleStopping(c)
|
||||
default:
|
||||
a.behavior.Receive(c)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialized handles UCAN operation messages once the actor is fully initialized.
|
||||
// This method is set as the behavior after the MPC enclave plugin is successfully loaded.
|
||||
// It processes NewOriginToken, NewAttenuatedToken, SignData, VerifyData, and GetIssuerDID requests.
|
||||
func (a *Actor) Initialized(c actor.Context) {
|
||||
switch msg := c.Message().(type) {
|
||||
case *NewOriginTokenRequest:
|
||||
a.handleNewOriginToken(c, msg)
|
||||
case *NewAttenuatedTokenRequest:
|
||||
a.handleNewAttenuatedToken(c, msg)
|
||||
case *SignDataRequest:
|
||||
a.handleSignData(c, msg)
|
||||
case *VerifyDataRequest:
|
||||
a.handleVerifyData(c, msg)
|
||||
case *GetIssuerDIDResponse: // Used as request for DID retrieval
|
||||
a.handleGetIssuerDID(c)
|
||||
}
|
||||
}
|
||||
|
||||
// handleStarted initializes the MPC enclave plugin when the actor starts.
|
||||
// It loads the WebAssembly plugin and transitions the actor to the initialized state.
|
||||
// If plugin loading fails, the actor remains in an uninitialized state.
|
||||
func (a *Actor) handleStarted(c actor.Context) {
|
||||
a.ctx = context.Background()
|
||||
|
||||
// Use provided config if available, otherwise use default
|
||||
var config *EnclaveConfig
|
||||
if a.config != nil {
|
||||
config = a.config
|
||||
} else {
|
||||
config = DefaultEnclaveConfig()
|
||||
}
|
||||
|
||||
// For testing, we need to provide mock enclave data
|
||||
// In production, this would be provided by the caller
|
||||
if config.EnclaveData == nil {
|
||||
c.Logger().Warn("No enclave data provided, actor will not initialize",
|
||||
slog.String("config", fmt.Sprintf("%+v", config)),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
c.Logger().Info("Attempting to load MPC enclave plugin",
|
||||
slog.String("config", fmt.Sprintf("%+v", config)),
|
||||
)
|
||||
|
||||
e, err := LoadPluginWithManager(a.ctx, config)
|
||||
if err != nil {
|
||||
c.Logger().Error("Failed to create MPC enclave host",
|
||||
slog.String("error", err.Error()),
|
||||
slog.String("config", fmt.Sprintf("%+v", config)),
|
||||
)
|
||||
return
|
||||
}
|
||||
a.enclave = e
|
||||
c.Logger().Info("MPC enclave actor started successfully",
|
||||
slog.String("config", fmt.Sprintf("%+v", config)),
|
||||
)
|
||||
a.behavior.Become(a.Initialized)
|
||||
}
|
||||
|
||||
// handleStopping performs cleanup when the actor is stopping.
|
||||
// It releases the MPC enclave plugin resources and cleans up the context.
|
||||
func (a *Actor) handleStopping(c actor.Context) {
|
||||
a.ctx.Done()
|
||||
a.enclave = nil
|
||||
c.Logger().Info("MPC enclave plugin done")
|
||||
}
|
||||
|
||||
// handleNewOriginToken processes UCAN origin token creation requests by delegating to the MPC enclave plugin.
|
||||
// It validates the request and responds with the generated UCAN token or an error.
|
||||
func (a *Actor) handleNewOriginToken(context actor.Context, msg *NewOriginTokenRequest) {
|
||||
resp, err := a.enclave.NewOriginToken(msg)
|
||||
if err != nil {
|
||||
context.Logger().Error("failed to create origin token", slog.String("error", err.Error()))
|
||||
context.Respond(err)
|
||||
return
|
||||
}
|
||||
context.Respond(resp)
|
||||
}
|
||||
|
||||
// handleNewAttenuatedToken processes UCAN attenuated token creation requests by delegating to the MPC enclave plugin.
|
||||
// It creates a delegated token with reduced permissions and responds with the token or an error.
|
||||
func (a *Actor) handleNewAttenuatedToken(context actor.Context, msg *NewAttenuatedTokenRequest) {
|
||||
resp, err := a.enclave.NewAttenuatedToken(msg)
|
||||
if err != nil {
|
||||
context.Logger().
|
||||
Error("failed to create attenuated token", slog.String("error", err.Error()))
|
||||
context.Respond(err)
|
||||
return
|
||||
}
|
||||
context.Respond(resp)
|
||||
}
|
||||
|
||||
// handleSignData processes data signing requests by delegating to the MPC enclave plugin.
|
||||
// It creates a cryptographic signature using MPC and responds with the signature or an error.
|
||||
func (a *Actor) handleSignData(context actor.Context, msg *SignDataRequest) {
|
||||
resp, err := a.enclave.SignData(msg)
|
||||
if err != nil {
|
||||
context.Logger().Error("failed to sign data", slog.String("error", err.Error()))
|
||||
context.Respond(err)
|
||||
return
|
||||
}
|
||||
context.Respond(resp)
|
||||
}
|
||||
|
||||
// handleVerifyData processes signature verification requests by delegating to the MPC enclave plugin.
|
||||
// It validates the signature against the data and responds with the verification result or an error.
|
||||
func (a *Actor) handleVerifyData(context actor.Context, msg *VerifyDataRequest) {
|
||||
resp, err := a.enclave.VerifyData(msg)
|
||||
if err != nil {
|
||||
context.Logger().Error("failed to verify data", slog.String("error", err.Error()))
|
||||
context.Respond(err)
|
||||
return
|
||||
}
|
||||
context.Respond(resp)
|
||||
}
|
||||
|
||||
// handleGetIssuerDID processes DID retrieval requests by delegating to the MPC enclave plugin.
|
||||
// It retrieves the issuer DID, address, and chain code from the enclave.
|
||||
func (a *Actor) handleGetIssuerDID(context actor.Context) {
|
||||
resp, err := a.enclave.GetIssuerDID()
|
||||
if err != nil {
|
||||
context.Logger().Error("failed to get issuer DID", slog.String("error", err.Error()))
|
||||
context.Respond(err)
|
||||
return
|
||||
}
|
||||
context.Respond(resp)
|
||||
}
|
||||
Reference in New Issue
Block a user