This commit is contained in:
programmer10110 2020-09-08 14:48:36 +03:00
parent 3856a364d8
commit 9617d92797
7 changed files with 301 additions and 151 deletions

View File

@ -40,7 +40,6 @@ type Poller interface {
ProcessMessage(message storage.Message) error
GetOperations() (map[string]*types.Operation, error)
GetOperationQRPath(operationID string) ([]string, error)
ReadProcessedOperation() error
StartHTTPServer(listenAddr string) error
GetLogger() *logger
}
@ -278,23 +277,6 @@ func (c *Client) GetOperationQRPath(operationID string) ([]string, error) {
return qrs, nil
}
// ReadProcessedOperation reads the processed operation from camera, checks that
// the processed operation has its unprocessed counterpart in our state,
// posts a Message to the storage and deletes the operation from our state.
func (c *Client) ReadProcessedOperation() error {
bz, err := qr.ReadDataFromQRChunks(c.qrProcessor)
if err != nil {
return fmt.Errorf("failed to ReadQR: %s", err)
}
var operation types.Operation
if err = json.Unmarshal(bz, &operation); err != nil {
return fmt.Errorf("failed to unmarshal processed operation")
}
return c.handleProcessedOperation(operation)
}
func (c *Client) handleProcessedOperation(operation types.Operation) error {
storedOperation, err := c.state.GetOperationByID(operation.ID)
if err != nil {

View File

@ -203,54 +203,3 @@ func TestClient_GetOperationQRPath(t *testing.T) {
req.NoError(err)
req.Equal(expectedQrPath, qrPath)
}
func TestClient_ReadProcessedOperation(t *testing.T) {
var (
ctx = context.Background()
req = require.New(t)
ctrl = gomock.NewController(t)
)
defer ctrl.Finish()
userName := "test_client"
keyStore := clientMocks.NewMockKeyStore(ctrl)
testClientKeyPair := client.NewKeyPair()
keyStore.EXPECT().LoadKeys(userName, "").Times(1).Return(testClientKeyPair, nil)
state := clientMocks.NewMockState(ctrl)
stg := storageMocks.NewMockStorage(ctrl)
qrProcessor := qrMocks.NewMockProcessor(ctrl)
clt, err := client.NewClient(
ctx,
userName,
state,
stg,
keyStore,
qrProcessor,
)
req.NoError(err)
operation := &types.Operation{
ID: "operation_id",
Type: types.DKGCommits,
Payload: []byte("operation_payload"),
CreatedAt: time.Now(),
}
processedOperation := &types.Operation{
ID: "operation_id",
Type: types.DKGCommits,
Payload: []byte("operation_payload"),
CreatedAt: time.Now(),
}
processedOperationBz, err := json.Marshal(processedOperation)
req.NoError(err)
qrProcessor.EXPECT().ReadQR().Return(processedOperationBz, nil).Times(1)
state.EXPECT().GetOperationByID(processedOperation.ID).Times(1).Return(operation, nil)
state.EXPECT().DeleteOperation(processedOperation.ID).Times(1)
err = clt.ReadProcessedOperation()
req.NoError(err)
}

View File

@ -62,7 +62,6 @@ func (c *Client) StartHTTPServer(listenAddr string) error {
mux.HandleFunc("/sendMessage", c.sendMessageHandler)
mux.HandleFunc("/getOperations", c.getOperationsHandler)
mux.HandleFunc("/getOperationQRPath", c.getOperationQRPathHandler)
mux.HandleFunc("/readProcessedOperationFromCamera", c.readProcessedOperationFromCameraHandler)
mux.HandleFunc("/readProcessedOperation", c.readProcessedOperationFromBodyHandler)
mux.HandleFunc("/getOperationQR", c.getOperationQRToBodyHandler)
@ -156,21 +155,6 @@ func (c *Client) getOperationQRToBodyHandler(w http.ResponseWriter, r *http.Requ
rawResponse(w, encodedData)
}
func (c *Client) readProcessedOperationFromCameraHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")
return
}
if err := c.ReadProcessedOperation(); err != nil {
errorResponse(w, http.StatusInternalServerError,
fmt.Sprintf("failed to handle processed operation from camera path: %v", err))
return
}
successResponse(w, "ok")
}
func (c *Client) readProcessedOperationFromBodyHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
errorResponse(w, http.StatusBadRequest, "Wrong HTTP method")

View File

@ -1,63 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"github.com/depools/dc4bc/client/types"
"github.com/spf13/cobra"
"io/ioutil"
"net/http"
)
type OperationsResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result map[string]*types.Operation `json:"result"`
}
func getOperations(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 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 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 := getOperations(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 {
fmt.Printf("Operation ID: %s\n", operation.ID)
operationBz, err := json.Marshal(operation)
if err != nil {
return fmt.Errorf("failed to marshal operation: %w", err)
}
fmt.Printf("Operation: %s\n", string(operationBz))
fmt.Println("-----------------------------------------------------")
}
return nil
},
}
}

260
cmd/dc4bc_cli/commands.go Normal file
View File

@ -0,0 +1,260 @@
package main
import (
"bufio"
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/depools/dc4bc/client"
"github.com/depools/dc4bc/client/types"
"github.com/depools/dc4bc/fsm/types/requests"
"github.com/spf13/cobra"
"io/ioutil"
"net/http"
"os"
"strconv"
"time"
)
type OperationsResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result map[string]*types.Operation `json:"result"`
}
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 {
fmt.Printf("Operation ID: %s\n", operation.ID)
operationBz, err := json.Marshal(operation)
if err != nil {
return fmt.Errorf("failed to marshal operation: %w", err)
}
fmt.Printf("Operation: %s\n", string(operationBz))
fmt.Println("-----------------------------------------------------")
}
return nil
},
}
}
type OperationQRPathsResponse struct {
ErrorMessage string `json:"error_message,omitempty"`
Result []string `json:"result"`
}
func getOperationsQRPathsRequest(host string, operationID string) (*OperationQRPathsResponse, error) {
resp, err := http.Get(fmt.Sprintf("http://%s/getOperationQRPath?operationID=%s", host, operationID))
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)
}
var response OperationQRPathsResponse
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{
Use: "get_operation_qr [operationID]",
Args: cobra.ExactArgs(1),
Short: "returns path to QR codes which contains the operation",
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)
}
operationID := args[0]
operations, err := getOperationsQRPathsRequest(listenAddr, operationID)
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)
}
fmt.Printf("List of paths to QR codes for operation %s:\n", operationID)
for idx, path := range operations.Result {
fmt.Printf("%d) QR code: %s\n", idx, path)
}
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 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{
Use: "read_from_camera",
Short: "opens the camera and reads QR codes which should contain a processed operation",
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)
}
response, err := rawGetRequest(fmt.Sprintf("http://%s/readProcessedOperationFromCamera", listenAddr))
if err != nil {
return fmt.Errorf("failed to get operations: %w", err)
}
if response.ErrorMessage != "" {
return fmt.Errorf("failed to read operation from camera: %s", response.ErrorMessage)
}
return nil
},
}
}
func startDKGCommand() *cobra.Command {
return &cobra.Command{
Use: "startDKG [participants count] [threshold]",
Args: cobra.ExactArgs(2),
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)
}
participantsCount, err := strconv.Atoi(args[0])
if err != nil {
return fmt.Errorf("failed to get participants count: %w", err)
}
if participantsCount < 0 {
return fmt.Errorf("invalid number of participants: %d", participantsCount)
}
threshold, err := strconv.Atoi(args[1])
if err != nil {
return fmt.Errorf("failed to get threshold: %w", err)
}
if participantsCount < 0 || threshold > participantsCount {
return fmt.Errorf("invalid threshold: %d", threshold)
}
reader := bufio.NewReader(os.Stdin)
var participants []*requests.SignatureProposalParticipantsEntry
for i := 0; i < participantsCount; i++ {
p := &requests.SignatureProposalParticipantsEntry{}
fmt.Printf("Enter a necessary data for participant %d:\n", i)
fmt.Printf("Enter address: ")
p.Addr, err = reader.ReadString('\n')
if err != nil {
return fmt.Errorf("failed to read addr: %w", err)
}
fmt.Printf("Enter pubkey (base64): ")
pubKeyStr, err := reader.ReadString('\n')
if err != nil {
return fmt.Errorf("failed to read pubKey: %w", err)
}
p.PubKey, err = base64.StdEncoding.DecodeString(pubKeyStr)
if err != nil {
return fmt.Errorf("failed to decode pubKey: %w", err)
}
fmt.Printf("Enter DKGPubKey (base64): ")
DKGPubKeyStr, err := reader.ReadString('\n')
if err != nil {
return fmt.Errorf("failed to read DKGPubKey: %w", err)
}
p.DkgPubKey, err = base64.StdEncoding.DecodeString(DKGPubKeyStr)
if err != nil {
return fmt.Errorf("failed to decode DKGPubKey: %w", err)
}
participants = append(participants, p)
}
messageData := requests.SignatureProposalParticipantsListRequest{
Participants: participants,
SigningThreshold: threshold,
CreatedAt: time.Now(),
}
messageDataBz, err := json.Marshal(messageData)
if err != nil {
return fmt.Errorf("failed to marshal SignatureProposalParticipantsListRequest: %v\n", err)
}
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 != "" {
return fmt.Errorf("failed to make HTTP request to start DKG: %w", err)
}
return nil
},
}
}

39
cmd/dc4bc_cli/main.go Normal file
View File

@ -0,0 +1,39 @@
package main
import (
"github.com/spf13/cobra"
"log"
)
const (
flagUserName = "username"
flagListenAddr = "listen_addr"
flagStateDBDSN = "state_dbdsn"
flagStorageDBDSN = "storage_dbdsn"
flagStoreDBDSN = "key_store_dbdsn"
)
func init() {
rootCmd.PersistentFlags().String(flagUserName, "testUser", "Username")
rootCmd.PersistentFlags().String(flagListenAddr, "localhost:8080", "Listen Address")
rootCmd.PersistentFlags().String(flagStateDBDSN, "./dc4bc_client_state", "State DBDSN")
rootCmd.PersistentFlags().String(flagStorageDBDSN, "./dc4bc_file_storage", "Storage DBDSN")
rootCmd.PersistentFlags().String(flagStoreDBDSN, "./dc4bc_key_store", "Key Store DBDSN")
}
var rootCmd = &cobra.Command{
Use: "dc4bc_cli",
Short: "dc4bc client cli utilities implementation",
}
func main() {
rootCmd.AddCommand(
getOperationsCommand(),
getOperationQRPathCommand(),
readOperationFromCameraCommand(),
startDKGCommand(),
)
if err := rootCmd.Execute(); err != nil {
log.Fatalf("Failed to execute root command: %v", err)
}
}

View File

@ -140,15 +140,14 @@ func startClientCommand() *cobra.Command {
}
var rootCmd = &cobra.Command{
Use: "dc4bc_client",
Short: "dc4bc client implementation",
Use: "dc4bc_d",
Short: "dc4bc client daemon implementation",
}
func main() {
rootCmd.AddCommand(
startClientCommand(),
genKeyPairCommand(),
getOperationsCommand(),
)
if err := rootCmd.Execute(); err != nil {
log.Fatalf("Failed to execute root command: %v", err)