2020-09-08 04:48:36 -07:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2020-09-10 14:51:35 -07:00
|
|
|
"bytes"
|
2020-09-16 06:27:47 -07:00
|
|
|
"crypto/md5"
|
2020-10-05 03:58:52 -07:00
|
|
|
"encoding/base64"
|
2020-09-10 14:51:35 -07:00
|
|
|
"encoding/hex"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2020-11-05 01:43:54 -08:00
|
|
|
"github.com/lidofinance/dc4bc/fsm/state_machines"
|
2020-09-10 14:51:35 -07:00
|
|
|
"io/ioutil"
|
2020-09-08 04:48:36 -07:00
|
|
|
"log"
|
2020-09-10 14:51:35 -07:00
|
|
|
"net/http"
|
2020-09-16 06:27:47 -07:00
|
|
|
"sort"
|
2020-10-16 04:00:04 -07:00
|
|
|
"strconv"
|
2020-10-09 06:23:28 -07:00
|
|
|
"strings"
|
2020-09-10 14:51:35 -07:00
|
|
|
"time"
|
|
|
|
|
2020-11-05 01:43:54 -08:00
|
|
|
"github.com/lidofinance/dc4bc/fsm/fsm"
|
|
|
|
"github.com/lidofinance/dc4bc/fsm/state_machines/signature_proposal_fsm"
|
|
|
|
"github.com/lidofinance/dc4bc/fsm/state_machines/signing_proposal_fsm"
|
|
|
|
"github.com/lidofinance/dc4bc/fsm/types/responses"
|
2020-09-29 07:31:31 -07:00
|
|
|
|
2020-11-05 01:43:54 -08:00
|
|
|
"github.com/lidofinance/dc4bc/client"
|
|
|
|
"github.com/lidofinance/dc4bc/fsm/types/requests"
|
2020-09-10 14:51:35 -07:00
|
|
|
"github.com/spf13/cobra"
|
2020-09-08 04:48:36 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2020-09-30 02:45:24 -07:00
|
|
|
flagListenAddr = "listen_addr"
|
|
|
|
flagFramesDelay = "frames_delay"
|
|
|
|
flagChunkSize = "chunk_size"
|
|
|
|
flagQRCodesFolder = "qr_codes_folder"
|
2020-09-08 04:48:36 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
rootCmd.PersistentFlags().String(flagListenAddr, "localhost:8080", "Listen Address")
|
2020-09-30 02:45:24 -07:00
|
|
|
rootCmd.PersistentFlags().Int(flagFramesDelay, 10, "Delay times between frames in 100ths of a second")
|
|
|
|
rootCmd.PersistentFlags().Int(flagChunkSize, 256, "QR-code's chunk size")
|
|
|
|
rootCmd.PersistentFlags().String(flagQRCodesFolder, "/tmp", "Folder to save QR codes")
|
2020-09-08 04:48:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
var rootCmd = &cobra.Command{
|
|
|
|
Use: "dc4bc_cli",
|
|
|
|
Short: "dc4bc client cli utilities implementation",
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
rootCmd.AddCommand(
|
|
|
|
getOperationsCommand(),
|
|
|
|
getOperationQRPathCommand(),
|
|
|
|
readOperationFromCameraCommand(),
|
|
|
|
startDKGCommand(),
|
2020-09-08 07:24:19 -07:00
|
|
|
proposeSignMessageCommand(),
|
2020-09-15 06:45:35 -07:00
|
|
|
getUsernameCommand(),
|
2020-09-10 04:51:53 -07:00
|
|
|
getPubKeyCommand(),
|
2020-09-16 06:27:47 -07:00
|
|
|
getHashOfStartDKGCommand(),
|
2020-10-05 03:58:52 -07:00
|
|
|
getSignaturesCommand(),
|
|
|
|
getSignatureCommand(),
|
2020-10-16 04:00:04 -07:00
|
|
|
saveOffsetCommand(),
|
|
|
|
getOffsetCommand(),
|
2020-10-09 06:23:28 -07:00
|
|
|
getFSMStatusCommand(),
|
2020-10-20 03:38:39 -07:00
|
|
|
getFSMListCommand(),
|
2020-11-02 01:56:40 -08:00
|
|
|
getSignatureDataCommand(),
|
2020-09-08 04:48:36 -07:00
|
|
|
)
|
|
|
|
if err := rootCmd.Execute(); err != nil {
|
|
|
|
log.Fatalf("Failed to execute root command: %v", err)
|
|
|
|
}
|
|
|
|
}
|
2020-09-10 14:51:35 -07:00
|
|
|
|
|
|
|
func getOperationsRequest(host string) (*OperationsResponse, error) {
|
|
|
|
resp, err := http.Get(fmt.Sprintf("http://%s/getOperations", host))
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get operations: %w", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
responseBody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var response OperationsResponse
|
|
|
|
if err = json.Unmarshal(responseBody, &response); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
|
|
|
}
|
|
|
|
return &response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getOperationsCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "get_operations",
|
|
|
|
Short: "returns all operations that should be processed on the airgapped machine",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
operations, err := getOperationsRequest(listenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get operations: %w", err)
|
|
|
|
}
|
|
|
|
if operations.ErrorMessage != "" {
|
|
|
|
return fmt.Errorf("failed to get operations: %s", operations.ErrorMessage)
|
|
|
|
}
|
|
|
|
for _, operation := range operations.Result {
|
2020-09-16 06:27:47 -07:00
|
|
|
fmt.Printf("DKG round ID: %s\n", operation.DKGIdentifier)
|
2020-09-10 14:51:35 -07:00
|
|
|
fmt.Printf("Operation ID: %s\n", operation.ID)
|
2020-09-16 06:27:47 -07:00
|
|
|
fmt.Printf("Description: %s\n", getShortOperationDescription(operation.Type))
|
|
|
|
if fsm.State(operation.Type) == signature_proposal_fsm.StateAwaitParticipantsConfirmations {
|
|
|
|
payloadHash, err := calcStartDKGMessageHash(operation.Payload)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get hash of start DKG message: %w", err)
|
|
|
|
}
|
|
|
|
fmt.Printf("Hash of the proposing DKG message - %s\n", hex.EncodeToString(payloadHash))
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
2020-09-17 00:43:23 -07:00
|
|
|
if fsm.State(operation.Type) == signing_proposal_fsm.StateSigningAwaitConfirmations {
|
|
|
|
var payload responses.SigningProposalParticipantInvitationsResponse
|
|
|
|
if err := json.Unmarshal(operation.Payload, &payload); err != nil {
|
|
|
|
return fmt.Errorf("failed to unmarshal operation payload")
|
|
|
|
}
|
|
|
|
msgHash := md5.Sum(payload.SrcPayload)
|
2020-11-02 05:17:01 -08:00
|
|
|
fmt.Printf("Hash of the data to sign - %s\n", hex.EncodeToString(msgHash[:]))
|
|
|
|
fmt.Printf("Signing ID: %s\n", payload.SigningId)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
fmt.Println("-----------------------------------------------------")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-05 03:58:52 -07:00
|
|
|
func getSignaturesRequest(host string, dkgID string) (*SignaturesResponse, error) {
|
|
|
|
resp, err := http.Get(fmt.Sprintf("http://%s/getSignatures?dkgID=%s", host, dkgID))
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get signatures: %w", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
responseBody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var response SignaturesResponse
|
|
|
|
if err = json.Unmarshal(responseBody, &response); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
|
|
|
}
|
|
|
|
return &response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSignaturesCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "get_signatures [dkgID]",
|
|
|
|
Args: cobra.ExactArgs(1),
|
|
|
|
Short: "returns all signatures for the given DKG round that were reconstructed on the airgapped machine",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
signatures, err := getSignaturesRequest(listenAddr, args[0])
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get signatures: %w", err)
|
|
|
|
}
|
|
|
|
if signatures.ErrorMessage != "" {
|
|
|
|
return fmt.Errorf("failed to get signatures: %s", signatures.ErrorMessage)
|
|
|
|
}
|
2020-11-02 05:17:01 -08:00
|
|
|
for sigID, signature := range signatures.Result {
|
|
|
|
fmt.Printf("Signing ID: %s\n", sigID)
|
2020-10-05 03:58:52 -07:00
|
|
|
for _, participantSig := range signature {
|
|
|
|
fmt.Printf("\tDKG round ID: %s\n", participantSig.DKGRoundID)
|
2020-11-02 02:56:02 -08:00
|
|
|
fmt.Printf("\tParticipant: %s\n", participantSig.Username)
|
2020-10-05 03:58:52 -07:00
|
|
|
fmt.Printf("\tReconstructed signature for the data: %s\n", base64.StdEncoding.EncodeToString(participantSig.Signature))
|
|
|
|
fmt.Println()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSignatureRequest(host string, dkgID, dataHash string) (*SignatureResponse, error) {
|
2020-11-02 02:56:02 -08:00
|
|
|
resp, err := http.Get(fmt.Sprintf("http://%s/getSignatureByID?dkgID=%s&id=%s", host, dkgID, dataHash))
|
2020-10-05 03:58:52 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get signatures: %w", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
responseBody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var response SignatureResponse
|
|
|
|
if err = json.Unmarshal(responseBody, &response); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
|
|
|
}
|
|
|
|
return &response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSignatureCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
2020-11-02 01:56:40 -08:00
|
|
|
Use: "get_signature [dkgID] [signing_id]",
|
2020-10-05 03:58:52 -07:00
|
|
|
Args: cobra.ExactArgs(2),
|
|
|
|
Short: "returns a list of reconstructed signatures of the signed data broadcasted by users",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
signatures, err := getSignatureRequest(listenAddr, args[0], args[1])
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get signatures: %w", err)
|
|
|
|
}
|
|
|
|
if signatures.ErrorMessage != "" {
|
|
|
|
return fmt.Errorf("failed to get signatures: %s", signatures.ErrorMessage)
|
|
|
|
}
|
|
|
|
for _, participantSig := range signatures.Result {
|
2020-11-02 02:56:02 -08:00
|
|
|
fmt.Printf("\tParticipant: %s\n", participantSig.Username)
|
2020-10-05 03:58:52 -07:00
|
|
|
fmt.Printf("\tReconstructed signature for the data: %s\n", base64.StdEncoding.EncodeToString(participantSig.Signature))
|
|
|
|
fmt.Println()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-02 01:56:40 -08:00
|
|
|
func getSignatureDataCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "get_signature_data [dkgID] [signing_id]",
|
|
|
|
Args: cobra.ExactArgs(2),
|
|
|
|
Short: "returns a data which was signed",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
signatures, err := getSignatureRequest(listenAddr, args[0], args[1])
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get signatures: %w", err)
|
|
|
|
}
|
|
|
|
if signatures.ErrorMessage != "" {
|
|
|
|
return fmt.Errorf("failed to get signatures: %s", signatures.ErrorMessage)
|
|
|
|
}
|
|
|
|
if len(signatures.Result) > 0 {
|
2020-11-02 02:56:02 -08:00
|
|
|
fmt.Println(string(signatures.Result[0].SrcPayload))
|
2020-11-02 01:56:40 -08:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-30 02:45:24 -07:00
|
|
|
func getOperationRequest(host string, operationID string) (*OperationResponse, error) {
|
|
|
|
resp, err := http.Get(fmt.Sprintf("http://%s/getOperation?operationID=%s", host, operationID))
|
2020-09-10 14:51:35 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get operation: %w", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
responseBody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read body: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-09-30 02:45:24 -07:00
|
|
|
var response OperationResponse
|
2020-09-10 14:51:35 -07:00
|
|
|
if err = json.Unmarshal(responseBody, &response); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
|
|
|
}
|
|
|
|
return &response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getOperationQRPathCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
2020-11-25 06:50:50 -08:00
|
|
|
Use: "write_operation [operationID]",
|
2020-09-10 14:51:35 -07:00
|
|
|
Args: cobra.ExactArgs(1),
|
2020-11-25 06:50:50 -08:00
|
|
|
Short: "returns path to a JSON file which contains the operation",
|
2020-09-10 14:51:35 -07:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
2020-09-30 02:45:24 -07:00
|
|
|
|
2020-09-10 14:51:35 -07:00
|
|
|
operationID := args[0]
|
2020-09-30 02:45:24 -07:00
|
|
|
operation, err := getOperationRequest(listenAddr, operationID)
|
2020-09-10 14:51:35 -07:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get operations: %w", err)
|
|
|
|
}
|
2020-09-29 08:16:20 -07:00
|
|
|
if operation.ErrorMessage != "" {
|
|
|
|
return fmt.Errorf("failed to get operations: %s", operation.ErrorMessage)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
2020-09-30 02:45:24 -07:00
|
|
|
|
2020-11-25 06:50:50 -08:00
|
|
|
outFileName := fmt.Sprintf("%s.json", args[0])
|
|
|
|
err = ioutil.WriteFile(outFileName, operation.Result, 0400)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to write result to %s: %w", outFileName, err)
|
2020-09-30 02:45:24 -07:00
|
|
|
}
|
|
|
|
|
2020-11-25 06:50:50 -08:00
|
|
|
fmt.Printf("wrote operation to %s\n", outFileName)
|
|
|
|
|
2020-09-10 14:51:35 -07:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func rawGetRequest(url string) (*client.Response, error) {
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get operations for node %w", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
responseBody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read body %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var response client.Response
|
|
|
|
if err = json.Unmarshal(responseBody, &response); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
|
|
|
}
|
|
|
|
return &response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getPubKeyCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "get_pubkey",
|
|
|
|
Short: "returns client's pubkey",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := rawGetRequest(fmt.Sprintf("http://%s//getPubKey", listenAddr))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get client's pubkey: %w", err)
|
|
|
|
}
|
|
|
|
if resp.ErrorMessage != "" {
|
2020-09-30 07:10:59 -07:00
|
|
|
return fmt.Errorf("failed to get client's pubkey: %v", resp.ErrorMessage)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
fmt.Println(resp.Result.(string))
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-16 04:00:04 -07:00
|
|
|
func saveOffsetCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "save_offset [offset]",
|
|
|
|
Short: "saves a new offset for a storage",
|
|
|
|
Args: cobra.ExactArgs(1),
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
offset, err := strconv.ParseUint(args[0], 10, 64)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to parse uint: %w", err)
|
|
|
|
}
|
|
|
|
req := map[string]uint64{"offset": offset}
|
|
|
|
data, err := json.Marshal(req)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to create request: %w", err)
|
|
|
|
}
|
|
|
|
resp, err := rawPostRequest(fmt.Sprintf("http://%s/saveOffset", listenAddr), "application/json", data)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to save offset: %w", err)
|
|
|
|
}
|
|
|
|
if resp.ErrorMessage != "" {
|
|
|
|
return fmt.Errorf("failed to save offset: %v", resp.ErrorMessage)
|
|
|
|
}
|
|
|
|
fmt.Println(resp.Result.(string))
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func getOffsetCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "get_offset",
|
|
|
|
Short: "returns a current offset for the storage",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := rawGetRequest(fmt.Sprintf("http://%s//getOffset", listenAddr))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get offset: %w", err)
|
|
|
|
}
|
|
|
|
if resp.ErrorMessage != "" {
|
|
|
|
return fmt.Errorf("failed to get offset: %v", resp.ErrorMessage)
|
|
|
|
}
|
|
|
|
fmt.Println(uint64(resp.Result.(float64)))
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-15 06:45:35 -07:00
|
|
|
func getUsernameCommand() *cobra.Command {
|
2020-09-10 14:51:35 -07:00
|
|
|
return &cobra.Command{
|
2020-09-15 06:45:35 -07:00
|
|
|
Use: "get_username",
|
|
|
|
Short: "returns client's username",
|
2020-09-10 14:51:35 -07:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
|
2020-09-15 06:45:35 -07:00
|
|
|
resp, err := rawGetRequest(fmt.Sprintf("http://%s//getUsername", listenAddr))
|
2020-09-10 14:51:35 -07:00
|
|
|
if err != nil {
|
2020-09-15 06:45:35 -07:00
|
|
|
return fmt.Errorf("failed to get client's username: %w", err)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
if resp.ErrorMessage != "" {
|
2020-09-30 07:10:59 -07:00
|
|
|
return fmt.Errorf("failed to get client's username: %v", resp.ErrorMessage)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
fmt.Println(resp.Result.(string))
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func rawPostRequest(url string, contentType string, data []byte) (*client.Response, error) {
|
|
|
|
resp, err := http.Post(url,
|
|
|
|
contentType, bytes.NewReader(data))
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to send HTTP request: %w", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
responseBody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read body %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var response client.Response
|
|
|
|
if err = json.Unmarshal(responseBody, &response); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
|
|
|
}
|
|
|
|
return &response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readOperationFromCameraCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
2020-11-25 06:50:50 -08:00
|
|
|
Use: "read_op [operation-id]",
|
|
|
|
Args: cobra.ExactArgs(1),
|
|
|
|
Short: "reads the file operation-id_res.json which should contain a processed operation",
|
2020-09-10 14:51:35 -07:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
|
2020-11-25 06:50:50 -08:00
|
|
|
opID := args[0]
|
|
|
|
d, err := ioutil.ReadFile(opID + "_res.json")
|
2020-09-10 14:51:35 -07:00
|
|
|
if err != nil {
|
2020-11-25 06:50:50 -08:00
|
|
|
return fmt.Errorf("failed to read response: %w", err)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
2020-11-25 06:50:50 -08:00
|
|
|
|
2020-09-10 14:51:35 -07:00
|
|
|
resp, err := rawPostRequest(fmt.Sprintf("http://%s/handleProcessedOperationJSON", listenAddr),
|
2020-11-25 06:50:50 -08:00
|
|
|
"application/json", d)
|
2020-09-10 14:51:35 -07:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to handle processed operation: %w", err)
|
|
|
|
}
|
|
|
|
if resp.ErrorMessage != "" {
|
2020-09-30 07:10:59 -07:00
|
|
|
return fmt.Errorf("failed to handle processed operation: %v", resp.ErrorMessage)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func startDKGCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
2020-09-15 03:01:33 -07:00
|
|
|
Use: "start_dkg [proposing_file]",
|
|
|
|
Args: cobra.ExactArgs(1),
|
2020-09-10 14:51:35 -07:00
|
|
|
Short: "sends a propose message to start a DKG process",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
|
2020-09-15 03:01:33 -07:00
|
|
|
dkgProposeFileData, err := ioutil.ReadFile(args[0])
|
2020-09-10 14:51:35 -07:00
|
|
|
if err != nil {
|
2020-09-15 03:01:33 -07:00
|
|
|
return fmt.Errorf("failed to read file: %w", err)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
2020-09-15 03:01:33 -07:00
|
|
|
var req requests.SignatureProposalParticipantsListRequest
|
|
|
|
if err = json.Unmarshal(dkgProposeFileData, &req); err != nil {
|
|
|
|
return fmt.Errorf("failed to unmarshal dkg proposing file: %w", err)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
|
2020-09-15 03:01:33 -07:00
|
|
|
if len(req.Participants) == 0 || req.SigningThreshold > len(req.Participants) {
|
|
|
|
return fmt.Errorf("invalid threshold: %d", req.SigningThreshold)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
2020-09-15 03:01:33 -07:00
|
|
|
req.CreatedAt = time.Now()
|
2020-09-10 14:51:35 -07:00
|
|
|
|
2020-09-15 03:01:33 -07:00
|
|
|
messageData := req
|
2020-09-10 14:51:35 -07:00
|
|
|
messageDataBz, err := json.Marshal(messageData)
|
|
|
|
if err != nil {
|
2020-09-29 07:31:31 -07:00
|
|
|
return fmt.Errorf("failed to marshal SignatureProposalParticipantsListRequest: %v", err)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
resp, err := rawPostRequest(fmt.Sprintf("http://%s/startDKG", listenAddr),
|
|
|
|
"application/json", messageDataBz)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to make HTTP request to start DKG: %w", err)
|
|
|
|
}
|
|
|
|
if resp.ErrorMessage != "" {
|
2020-09-30 07:10:59 -07:00
|
|
|
return fmt.Errorf("failed to make HTTP request to start DKG: %v", resp.ErrorMessage)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 06:27:47 -07:00
|
|
|
func getHashOfStartDKGCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "get_start_dkg_file_hash [proposing_file]",
|
|
|
|
Args: cobra.ExactArgs(1),
|
|
|
|
Short: "returns hash of proposing message for DKG start to verify correctness",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
|
|
|
|
dkgProposeFileData, err := ioutil.ReadFile(args[0])
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read file: %w", err)
|
|
|
|
}
|
|
|
|
var req requests.SignatureProposalParticipantsListRequest
|
|
|
|
if err = json.Unmarshal(dkgProposeFileData, &req); err != nil {
|
|
|
|
return fmt.Errorf("failed to unmarshal dkg proposing file: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
participants := DKGParticipants(req.Participants)
|
|
|
|
sort.Sort(participants)
|
|
|
|
|
|
|
|
hashPayload := bytes.NewBuffer(nil)
|
|
|
|
if _, err := hashPayload.Write([]byte(fmt.Sprintf("%d", req.SigningThreshold))); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, p := range participants {
|
|
|
|
if _, err := hashPayload.Write(p.PubKey); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if _, err := hashPayload.Write(p.DkgPubKey); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-10-28 03:16:20 -07:00
|
|
|
if _, err := hashPayload.Write([]byte(p.Username)); err != nil {
|
2020-09-16 06:27:47 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hash := md5.Sum(hashPayload.Bytes())
|
|
|
|
fmt.Println(hex.EncodeToString(hash[:]))
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-10 14:51:35 -07:00
|
|
|
func proposeSignMessageCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
2020-10-02 01:50:00 -07:00
|
|
|
Use: "sign_data [dkg_id] [file_path]",
|
2020-09-10 14:51:35 -07:00
|
|
|
Args: cobra.ExactArgs(2),
|
2020-10-02 01:50:00 -07:00
|
|
|
Short: "sends a propose message to sign the data in the file",
|
2020-09-10 14:51:35 -07:00
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
dkgID, err := hex.DecodeString(args[0])
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to decode dkgID: %w", err)
|
|
|
|
}
|
|
|
|
|
2020-10-02 01:50:00 -07:00
|
|
|
data, err := ioutil.ReadFile(args[1])
|
2020-09-10 14:51:35 -07:00
|
|
|
if err != nil {
|
2020-10-02 01:50:00 -07:00
|
|
|
return fmt.Errorf("failed to read the file")
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
|
2020-10-02 04:49:32 -07:00
|
|
|
messageDataBz, err := json.Marshal(map[string][]byte{"data": data,
|
2020-09-10 14:51:35 -07:00
|
|
|
"dkgID": dkgID})
|
|
|
|
if err != nil {
|
2020-09-29 07:31:31 -07:00
|
|
|
return fmt.Errorf("failed to marshal SigningProposalStartRequest: %v", err)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := rawPostRequest(fmt.Sprintf("http://%s/proposeSignMessage", listenAddr),
|
|
|
|
"application/json", messageDataBz)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to make HTTP request to propose message to sign: %w", err)
|
|
|
|
}
|
|
|
|
if resp.ErrorMessage != "" {
|
2020-09-30 07:10:59 -07:00
|
|
|
return fmt.Errorf("failed to make HTTP request to propose message to sign: %v", resp.ErrorMessage)
|
2020-09-10 14:51:35 -07:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2020-10-09 06:23:28 -07:00
|
|
|
|
|
|
|
func getFSMDumpRequest(host string, dkgID string) (*FSMDumpResponse, error) {
|
|
|
|
resp, err := http.Get(fmt.Sprintf("http://%s/getFSMDump?dkgID=%s", host, dkgID))
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to get FSM dump: %w", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
|
|
responseBody, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read body: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var response FSMDumpResponse
|
|
|
|
if err = json.Unmarshal(responseBody, &response); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to unmarshal response: %v", err)
|
|
|
|
}
|
|
|
|
return &response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getFSMStatusCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "show_fsm_status [dkg_id]",
|
|
|
|
Args: cobra.ExactArgs(1),
|
|
|
|
Short: "shows the current status of FSM",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
fsmDumpResponse, err := getFSMDumpRequest(listenAddr, args[0])
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to get FSM dump: %w", err)
|
|
|
|
}
|
|
|
|
if fsmDumpResponse.ErrorMessage != "" {
|
|
|
|
return fmt.Errorf("failed to get FSM dump: %v", fsmDumpResponse.ErrorMessage)
|
|
|
|
}
|
|
|
|
dump := fsmDumpResponse.Result
|
|
|
|
|
2020-10-12 05:14:19 -07:00
|
|
|
fmt.Printf("FSM current status is %s\n", dump.State)
|
2020-10-09 06:23:28 -07:00
|
|
|
|
|
|
|
quorum := make(map[int]state_machines.Participant)
|
|
|
|
if strings.HasPrefix(string(dump.State), "state_signing") {
|
|
|
|
for k, v := range dump.Payload.SigningProposalPayload.Quorum {
|
|
|
|
quorum[k] = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if strings.HasPrefix(string(dump.State), "state_dkg") {
|
|
|
|
for k, v := range dump.Payload.DKGProposalPayload.Quorum {
|
|
|
|
quorum[k] = v
|
|
|
|
}
|
|
|
|
}
|
2020-10-26 03:23:32 -07:00
|
|
|
if strings.HasPrefix(string(dump.State), "state_sig_") {
|
2020-10-09 06:23:28 -07:00
|
|
|
for k, v := range dump.Payload.SignatureProposalPayload.Quorum {
|
|
|
|
quorum[k] = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-19 02:56:00 -07:00
|
|
|
waiting := make([]string, 0)
|
|
|
|
confirmed := make([]string, 0)
|
|
|
|
failed := make([]string, 0)
|
|
|
|
|
2020-10-09 06:23:28 -07:00
|
|
|
for _, p := range quorum {
|
|
|
|
if strings.Contains(p.GetStatus().String(), "Await") {
|
2020-10-28 03:16:20 -07:00
|
|
|
waiting = append(waiting, p.GetUsername())
|
2020-10-09 06:23:28 -07:00
|
|
|
}
|
|
|
|
if strings.Contains(p.GetStatus().String(), "Error") {
|
2020-10-28 03:16:20 -07:00
|
|
|
failed = append(failed, p.GetUsername())
|
2020-10-09 06:23:28 -07:00
|
|
|
}
|
|
|
|
if strings.Contains(p.GetStatus().String(), "Confirmed") {
|
2020-10-28 03:16:20 -07:00
|
|
|
confirmed = append(confirmed, p.GetUsername())
|
2020-10-09 06:23:28 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-19 02:56:00 -07:00
|
|
|
if len(waiting) > 0 {
|
|
|
|
fmt.Printf("Waiting for a data from: %s\n", strings.Join(waiting, ", "))
|
|
|
|
}
|
|
|
|
if len(confirmed) > 0 {
|
|
|
|
fmt.Printf("Received a data from: %s\n", strings.Join(confirmed, ", "))
|
|
|
|
}
|
|
|
|
if len(failed) > 0 {
|
|
|
|
fmt.Printf("Participants who got some error during a process: %s\n", strings.Join(waiting, ", "))
|
|
|
|
}
|
|
|
|
|
2020-10-09 06:23:28 -07:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2020-10-20 03:38:39 -07:00
|
|
|
|
|
|
|
func getFSMListCommand() *cobra.Command {
|
|
|
|
return &cobra.Command{
|
|
|
|
Use: "get_fsm_list",
|
|
|
|
Short: "returns a list of all FSMs served by the client",
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
|
|
listenAddr, err := cmd.Flags().GetString(flagListenAddr)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read configuration: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := rawGetRequest(fmt.Sprintf("http://%s/getFSMList", listenAddr))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to make HTTP request to get FSM list: %w", err)
|
|
|
|
}
|
|
|
|
if resp.ErrorMessage != "" {
|
|
|
|
return fmt.Errorf("failed to make HTTP request to get FSM list: %v", resp.ErrorMessage)
|
|
|
|
}
|
|
|
|
fsms := resp.Result.(map[string]interface{})
|
|
|
|
for dkgID, state := range fsms {
|
|
|
|
fmt.Printf("DKG ID: %s - FSM state: %s\n", dkgID, state.(string))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|