Skip to content

Commit

Permalink
feat(clichain): adds a way of operating a keychain from CLI (#113)
Browse files Browse the repository at this point in the history
* fix(wardend): marshalling of SignatureRequest in terminal

* feat(x/warden): add cli commands to fulfill/reject a signature request

* feat(clichain): add basic cli tool for generating keys and signatures

* docs: add runbook to operate a keychain using clichain
  • Loading branch information
Pitasi authored Mar 21, 2024
1 parent e4c1290 commit 4231662
Show file tree
Hide file tree
Showing 9 changed files with 548 additions and 105 deletions.
141 changes: 73 additions & 68 deletions api/warden/warden/v1beta2/signature.pulsar.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

197 changes: 197 additions & 0 deletions cmd/clichain/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package main

import (
"encoding/base64"
"encoding/hex"
"fmt"
"io"
"os"

"github.com/ethereum/go-ethereum/crypto"
"github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
Use: "clichain",
Short: "clichain is a CLI tool for ECDSA secp256k1 key generation and signing",
}

var generateCmd = &cobra.Command{
Use: "generate",
Short: "Generate a new private key",
Long: `Generates a new private key and saves it to a specified output file.`,
RunE: func(cmd *cobra.Command, args []string) error {
output, err := cmd.Flags().GetString("output")
if err != nil {
return fmt.Errorf("reading output file: %w", err)
}

key, err := crypto.GenerateKey()
if err != nil {
return fmt.Errorf("generating key: %w", err)
}

keybin := crypto.FromECDSA(key)

w := os.Stdout
if output != "" {
f, err := os.OpenFile(output, os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return fmt.Errorf("opening output file: %w", err)
}
defer f.Close()
w = f
}

if _, err := w.Write([]byte(hex.EncodeToString(keybin))); err != nil {
return fmt.Errorf("writing key to file: %w", err)
}

return nil
},
}

var publicKeyCmd = &cobra.Command{
Use: "public-key",
Short: "Derive the public key from a private key",
RunE: func(cmd *cobra.Command, args []string) error {
keyFile, err := cmd.Flags().GetString("key")
if err != nil {
return fmt.Errorf("reading flag: %w", err)
}

in := os.Stdin
if keyFile != "" {
f, err := os.Open(keyFile)
if err != nil {
return fmt.Errorf("opening key file: %w", err)
}
in = f
}

keyHex, err := io.ReadAll(in)
if err != nil {
return fmt.Errorf("reading key: %w", err)
}

key, err := crypto.HexToECDSA(string(keyHex))
if err != nil {
return fmt.Errorf("parsing key: %w", err)
}

pubKey := crypto.CompressPubkey(&key.PublicKey)

output, err := cmd.Flags().GetString("output")
if err != nil {
return fmt.Errorf("reading output format: %w", err)
}

switch output {
case "binary":
os.Stdout.Write(pubKey)
case "hex":
os.Stdout.Write([]byte(hex.EncodeToString(pubKey)))
case "base64":
os.Stdout.Write([]byte(base64.StdEncoding.EncodeToString(pubKey)))
default:
return fmt.Errorf("unknown output format: %s", output)
}

return nil
},
}

var signCmd = &cobra.Command{
Use: "sign",
Short: "Sign a message using a private key",
Long: `Signs a message using the specified private key.`,
RunE: func(cmd *cobra.Command, args []string) error {
keyFile, err := cmd.Flags().GetString("key")
if err != nil {
return fmt.Errorf("reading flag: %w", err)
}

messageFile, err := cmd.Flags().GetString("message")
if err != nil {
return fmt.Errorf("reading flag: %w", err)
}

f, err := os.Open(keyFile)
if err != nil {
return fmt.Errorf("opening key file: %w", err)
}
defer f.Close()

keyHex, err := os.ReadFile(keyFile)
if err != nil {
return fmt.Errorf("reading key file: %w", err)
}

key, err := crypto.HexToECDSA(string(keyHex))
if err != nil {
return fmt.Errorf("parsing key: %w", err)
}

in := os.Stdin
if messageFile != "" {
f, err := os.Open(messageFile)
if err != nil {
return fmt.Errorf("opening message file: %w", err)
}
in = f
}

message, err := io.ReadAll(in)
if err != nil {
return fmt.Errorf("reading message: %w", err)
}

sig, err := crypto.Sign(message, key)
if err != nil {
return fmt.Errorf("signing message: %w", err)
}

output, err := cmd.Flags().GetString("output")
if err != nil {
return fmt.Errorf("reading output format: %w", err)
}

switch output {
case "binary":
os.Stdout.Write(sig)
case "hex":
os.Stdout.Write([]byte(hex.EncodeToString(sig)))
case "base64":
os.Stdout.Write([]byte(base64.StdEncoding.EncodeToString(sig)))
default:
return fmt.Errorf("unknown output format: %s", output)
}

return nil
},
}

func init() {
rootCmd.AddCommand(generateCmd)
rootCmd.AddCommand(publicKeyCmd)
rootCmd.AddCommand(signCmd)

// Here we define the flags for the generate command
generateCmd.Flags().StringP("output", "o", "", "Output file for the private key")

// Here we define the flags for the publicKey command
publicKeyCmd.Flags().StringP("key", "k", "private.key", "Private key file to use for signing")
publicKeyCmd.Flags().StringP("output", "o", "binary", "Output format for the public key (binary | hex | base64)")

// Here we define the flags for the sign command
signCmd.Flags().StringP("key", "k", "private.key", "Private key file to use for signing")
signCmd.Flags().StringP("message", "m", "", "Message file containing the digest to be signed")
signCmd.Flags().StringP("output", "o", "binary", "Output format for the signature (binary | hex | base64)")
}

func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
8 changes: 8 additions & 0 deletions docs/docs/developers/runbooks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Runbooks

This directory contains documents useful for who is developing the Warden
Protocol.

Every document in this directory is a runbook, which is a set of instructions
to guide the reader through a process, without necessarily providing a
high-level overview or explaination of the process itself.
5 changes: 5 additions & 0 deletions docs/docs/developers/runbooks/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"label": "Runbooks",
"position": 90,
"link": { "type": "doc", "id": "developers/runbooks/README" }
}
Loading

0 comments on commit 4231662

Please sign in to comment.