Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raw mode input for device recovery #5

Merged
merged 4 commits into from
Mar 19, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add character and word position to raw prompt. Update cli for raw mod…
…e flag. Default=true
  • Loading branch information
solipsis committed Mar 17, 2018
commit 176368e74b7699ef86d43aeb327232f71b108f7c
16 changes: 8 additions & 8 deletions cmd/recoverDevice.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ func init() {
recoverDeviceCmd.Flags().Uint32VarP(&numWords, "numWords", "n", 12, "number of words for seed (12, 18, 24)")
recoverDeviceCmd.Flags().BoolVarP(&enforceWordList, "wordList", "", false, "enforce device word list")
recoverDeviceCmd.Flags().BoolVarP(&useCharacterCipher, "characterCipher", "c", true, "use device character cipher")
recoverDeviceCmd.Flags().BoolVarP(&rawMode, "rawMode", "r", true, "Raw input mode for recovery. May not be available for all shell environments")
rootCmd.AddCommand(recoverDeviceCmd)
}

var numWords uint32
var enforceWordList bool
var useCharacterCipher bool
var (
numWords uint32
enforceWordList bool
useCharacterCipher bool
rawMode bool
)

var recoverDeviceCmd = &cobra.Command{
Use: "recoverDevice",
Short: "Begin interactive device recovery",
Long: `Begin the interactive device recovery workflow. The device must be uninitialized in order to recover it. See [wipeDevice]`,
Run: func(cmd *cobra.Command, args []string) {
//if err := kk.RecoverDevice(numWords, enforceWordList, useCharacterCipher); err != nil {
//fmt.Println(err)
//os.Exit(1)
//}
if err := kk.RecoverDeviceRaw(numWords, enforceWordList); err != nil {
if err := kk.RecoverDevice(numWords, enforceWordList, useCharacterCipher, rawMode); err != nil {
fmt.Println(err)
os.Exit(1)
}
Expand Down
18 changes: 18 additions & 0 deletions pkg/keepkey/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"math/big"
"strconv"
"strings"
"unicode/utf8"

Expand Down Expand Up @@ -130,11 +131,15 @@ func (kk *Keepkey) VerifyMessage(addr, coinName string, msg, sig []byte) error {
return err
}

// Recovery process that consumes each input as it is typed providing
// a better user experience than the prompt version
func (kk *Keepkey) recoverDeviceRaw(numWords uint32, enforceWordlist bool) error {

// TODO: stylings in seperate file?
cyan := color.New(color.FgCyan).Add(color.Bold).SprintFunc()
magenta := color.New(color.FgMagenta).Add(color.Underline).Add(color.Bold).SprintFunc()
yellow := color.New(color.FgYellow).Add(color.Underline).Add(color.Bold).SprintFunc()
green := color.New(color.FgGreen).Add(color.Underline).Add(color.Bold).SprintFunc()
fmt.Println(cyan("\nUse the character cipher on the device to enter your recovery words"))
fmt.Println(cyan("When the word is complete on the device use "), yellow("<space>"), cyan(" to continue to the next word"))
fmt.Println(cyan("Use "), yellow("<backspace>"), cyan(" or "), yellow("<delete>"), cyan(" to go back"))
Expand Down Expand Up @@ -162,10 +167,15 @@ func (kk *Keepkey) recoverDeviceRaw(numWords uint32, enforceWordlist bool) error
return err
}

// Setup prompts
position := green("Word #"+strconv.Itoa(int(req.GetWordPos()+1))) + " | " +
green("letter #"+strconv.Itoa(int(req.GetCharacterPos()+1))) + "\n"
prefix := []rune(magenta("Enter words:"))
in := make([]byte, 4) // Input buffer for any utf8 character
buf := make([]rune, 0) // Obscured buffer of all recieved input
buf = append(buf, prefix...)
t.Write([]byte(position))
t.Write([]byte("\r"))
t.Write([]byte(string(buf)))

var wordNum uint32
Expand Down Expand Up @@ -201,7 +211,13 @@ func (kk *Keepkey) recoverDeviceRaw(numWords uint32, enforceWordlist bool) error
}

// redraw prompt
position = green("Word #"+strconv.Itoa(int(req.GetWordPos()+1))) + " | " +
green("letter #"+strconv.Itoa(int(req.GetCharacterPos()+1))) + "\n"
wordNum = req.GetWordPos()
t.Write([]byte("\033[F"))
t.Write([]byte("\033[2K"))
t.Write([]byte("\r"))
t.Write([]byte(position))
t.Write([]byte("\033[2K"))
t.Write([]byte("\r"))
t.Write([]byte(string(buf)))
Expand All @@ -220,13 +236,15 @@ func (kk *Keepkey) recoverDeviceRaw(numWords uint32, enforceWordlist bool) error
// RecoverDevice initiates the interactive seed recovery process in which the user is asked to input their seed words
// The useCharacterCipher flag tells the device to recover using the on-screen cypher or through entering
// the words in a random order. This method must be called on an uninitialized device
// Raw Mode provides a superior user experience but may not be available in all shell environments
func (kk *Keepkey) RecoverDevice(numWords uint32, enforceWordList, useCharacterCipher, rawMode bool) error {
if rawMode {
return kk.recoverDeviceRaw(numWords, enforceWordList)
}
return kk.recoverDevicePrompt(numWords, enforceWordList, useCharacterCipher)
}

// Recovery process that repeatedly prompts the user for each character
func (kk *Keepkey) recoverDevicePrompt(numWords uint32, enforceWordlist, useCharacterCipher bool) error {

recover := &kkProto.RecoveryDevice{
Expand Down