diff --git a/airgapped/airgapped.go b/airgapped/airgapped.go index 28fc8aeb..948c9e80 100644 --- a/airgapped/airgapped.go +++ b/airgapped/airgapped.go @@ -29,17 +29,17 @@ const ( type Machine struct { sync.Mutex - dkgInstances map[string]*dkg.DKG - qrProcessor qr.Processor + ResultQRFolder string + dkgInstances map[string]*dkg.DKG encryptionKey []byte pubKey kyber.Point secKey kyber.Scalar baseSuite vss.Suite baseSeed []byte - db *leveldb.DB - resultQRFolder string + qrProcessor qr.Processor + db *leveldb.DB } func NewMachine(dbPath string) (*Machine, error) { @@ -83,7 +83,7 @@ func (am *Machine) SetQRProcessorChunkSize(chunkSize int) { } func (am *Machine) SetResultQRFolder(resultQRFolder string) { - am.resultQRFolder = resultQRFolder + am.ResultQRFolder = resultQRFolder } // InitKeys load keys public and private keys for DKG from LevelDB. If keys does not exist, creates them. @@ -162,7 +162,7 @@ func (am *Machine) ProcessOperation(operation client.Operation, storeOperation b return "", fmt.Errorf("failed to marshal operation: %w", err) } - qrPath := filepath.Join(am.resultQRFolder, fmt.Sprintf("dc4bc_qr_%s-response.gif", resultOperation.ID)) + qrPath := filepath.Join(am.ResultQRFolder, fmt.Sprintf("dc4bc_qr_%s-response.gif", resultOperation.ID)) if err = am.qrProcessor.WriteQR(qrPath, operationBz); err != nil { return "", fmt.Errorf("failed to write QR: %w", err) } diff --git a/cmd/airgapped/main.go b/cmd/airgapped/main.go index 0a18a660..faba3dd8 100644 --- a/cmd/airgapped/main.go +++ b/cmd/airgapped/main.go @@ -7,19 +7,24 @@ import ( "encoding/json" "flag" "fmt" - client "github.com/lidofinance/dc4bc/client/types" - "github.com/syndtr/goleveldb/leveldb" "io" "io/ioutil" "log" "os" "os/signal" + "path/filepath" "runtime" + "sort" "strconv" "strings" "syscall" "time" + "github.com/lidofinance/dc4bc/qr" + + client "github.com/lidofinance/dc4bc/client/types" + "github.com/syndtr/goleveldb/leveldb" + "golang.org/x/crypto/ssh/terminal" "github.com/lidofinance/dc4bc/airgapped" @@ -51,7 +56,7 @@ type prompt struct { func NewPrompt(machine *airgapped.Machine) (*prompt, error) { p := prompt{ - reader: bufio.NewReaderSize(os.Stdin, 1 << 22), + reader: bufio.NewReaderSize(os.Stdin, 1<<22), airgapped: machine, commands: make(map[string]*promptCommand), currentCommand: "", @@ -100,6 +105,10 @@ func NewPrompt(machine *airgapped.Machine) (*prompt, error) { commandHandler: p.changeConfigurationCommand, description: "changes a configuration variables (frames delay, chunk size, etc...)", }) + p.addCommand("generate_dkg_pubkey_qr", &promptCommand{ + commandHandler: p.generateDKGPubKeyQR, + description: "generates and saves a QR with DKG public key that can be read by the Client node", + }) return &p, nil } @@ -181,10 +190,17 @@ func (p *prompt) showDKGPubKeyCommand() error { } func (p *prompt) helpCommand() error { + var commandNames []string + for commandName := range p.commands { + commandNames = append(commandNames, commandName) + } + sort.Strings(commandNames) + p.println("Available commands:") - for commandName, command := range p.commands { - p.printf("* %s - %s\n", commandName, command.description) + for _, commandName := range commandNames { + p.printf("* %s - %s\n", commandName, p.commands[commandName].description) } + return nil } @@ -325,6 +341,30 @@ func (p *prompt) verifySignCommand() error { return nil } +func (p *prompt) generateDKGPubKeyQR() error { + dkgPubKey := p.airgapped.GetPubKey() + dkgPubKeyBz, err := dkgPubKey.MarshalBinary() + if err != nil { + return fmt.Errorf("failed to marshal DKG pub key: %w", err) + } + + dkgPubKeyBase64 := base64.StdEncoding.EncodeToString(dkgPubKeyBz) + dkgPubKeyJSON, err := json.Marshal(map[string]string{"dkg_pub_key": dkgPubKeyBase64}) + if err != nil { + return fmt.Errorf("failed to marshal operation: %w", err) + } + + qrProcessor := qr.NewCameraProcessor() + qrPath := filepath.Join(p.airgapped.ResultQRFolder, fmt.Sprintf("dc4bc_qr_dkg_pub_key.gif")) + if err = qrProcessor.WriteQR(qrPath, dkgPubKeyJSON); err != nil { + return fmt.Errorf("failed to write QR: %w", err) + } + + p.printf("A QR code with DKG public key was saved to: %s\n", qrPath) + + return nil +} + func (p *prompt) enterEncryptionPasswordIfNeeded() error { p.airgapped.Lock() defer p.airgapped.Unlock()