mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-04 18:31:41 +00:00
@@ -0,0 +1,157 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
|
||||
"github.com/sonr-io/sonr/x/dwn/client/plugin"
|
||||
)
|
||||
|
||||
// SignCmd returns a command to sign data or transactions using the Motor plugin
|
||||
func SignCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "sign [message-or-file]",
|
||||
Short: "Sign a message or transaction using Motor plugin",
|
||||
Long: `Sign a message or transaction using the Motor plugin's MPC-based signing.
|
||||
|
||||
Examples:
|
||||
# Sign a text message
|
||||
snrd wallet sign "Hello World" --enclave-data @enclave.json
|
||||
|
||||
# Sign a transaction file
|
||||
snrd wallet sign @unsigned_tx.json --enclave-data @enclave.json --tx
|
||||
|
||||
# Sign raw bytes (hex encoded)
|
||||
snrd wallet sign 0xdeadbeef --enclave-data @enclave.json`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
clientCtx, err := client.GetClientQueryContext(cmd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get enclave data
|
||||
enclaveDataStr, err := cmd.Flags().GetString("enclave-data")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if enclaveDataStr == "" {
|
||||
return fmt.Errorf("--enclave-data flag is required")
|
||||
}
|
||||
|
||||
enclaveData, err := parseEnclaveData(enclaveDataStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse enclave data: %w", err)
|
||||
}
|
||||
|
||||
// Determine what to sign
|
||||
input := args[0]
|
||||
var dataToSign []byte
|
||||
|
||||
isTransaction, _ := cmd.Flags().GetBool("tx")
|
||||
|
||||
if input[0] == '@' {
|
||||
// Read from file
|
||||
fileData, err := os.ReadFile(input[1:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read file: %w", err)
|
||||
}
|
||||
|
||||
if isTransaction {
|
||||
// For transaction, just use the raw bytes
|
||||
// In a real implementation, we'd extract sign bytes properly
|
||||
dataToSign = fileData
|
||||
} else {
|
||||
dataToSign = fileData
|
||||
}
|
||||
} else if len(input) > 2 && input[:2] == "0x" {
|
||||
// Hex encoded data
|
||||
dataToSign, err = hex.DecodeString(input[2:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode hex: %w", err)
|
||||
}
|
||||
} else {
|
||||
// Plain text message
|
||||
dataToSign = []byte(input)
|
||||
}
|
||||
|
||||
// Load the plugin
|
||||
chainID := clientCtx.ChainID
|
||||
if chainID == "" {
|
||||
chainID = DefaultTestChainID
|
||||
}
|
||||
config := plugin.CreateEnclaveConfig(chainID, enclaveData)
|
||||
|
||||
ctx := context.Background()
|
||||
motorPlugin, err := plugin.LoadPluginWithManager(ctx, config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load Motor plugin: %w", err)
|
||||
}
|
||||
|
||||
// Sign the data
|
||||
signReq := &plugin.SignDataRequest{
|
||||
Data: dataToSign,
|
||||
}
|
||||
signResp, err := motorPlugin.SignData(signReq)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign data: %w", err)
|
||||
}
|
||||
|
||||
if signResp.Error != "" {
|
||||
return fmt.Errorf("plugin signing error: %s", signResp.Error)
|
||||
}
|
||||
|
||||
// Get issuer info for display
|
||||
issuerResp, _ := motorPlugin.GetIssuerDID()
|
||||
|
||||
// Output the signature
|
||||
result := map[string]any{
|
||||
"signature": hex.EncodeToString(signResp.Signature),
|
||||
"signer": map[string]any{
|
||||
"did": issuerResp.IssuerDID,
|
||||
"address": issuerResp.Address,
|
||||
},
|
||||
"data_hash": hex.EncodeToString(dataToSign[:min(32, len(dataToSign))]),
|
||||
}
|
||||
|
||||
// Save to file if requested
|
||||
outputFile, _ := cmd.Flags().GetString("output-file")
|
||||
if outputFile != "" {
|
||||
jsonData, err := json.MarshalIndent(result, "", " ")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal result: %w", err)
|
||||
}
|
||||
if err := os.WriteFile(outputFile, jsonData, 0o644); err != nil {
|
||||
return fmt.Errorf("failed to write output file: %w", err)
|
||||
}
|
||||
fmt.Printf("Signature saved to %s\n", outputFile)
|
||||
}
|
||||
|
||||
return clientCtx.PrintObjectLegacy(result)
|
||||
},
|
||||
}
|
||||
|
||||
flags.AddQueryFlagsToCmd(cmd)
|
||||
cmd.Flags().String("enclave-data", "", "Enclave data for signing (required)")
|
||||
cmd.Flags().Bool("tx", false, "Sign as transaction (parse JSON as tx)")
|
||||
cmd.Flags().String("output-file", "", "Save signature to file")
|
||||
cmd.MarkFlagRequired("enclave-data")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
Reference in New Issue
Block a user