Files
sonr/x/dwn/client/cli/sign.go
T
Prad NukalaandGitHub 13e6c3e84d Master (#1262)
* clear

* feat: Add everything

* fix: Commenht
2025-10-03 14:45:52 -04:00

158 lines
4.0 KiB
Go

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
}