Fix Mnemonic Validation (#10354)

* fix mnemonic validation

* potuz's review

* Add fuzz test for wallet recover

Co-authored-by: prestonvanloon <preston@prysmaticlabs.com>
This commit is contained in:
Nishant Das 2022-03-14 07:30:11 +08:00 committed by GitHub
parent 3f1e3cf82f
commit 58f7e942f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 89 additions and 5 deletions

View File

@ -70,8 +70,10 @@ go_test(
"accounts_list_test.go",
"wallet_create_test.go",
"wallet_edit_test.go",
"wallet_recover_fuzz_test.go",
"wallet_recover_test.go",
],
data = glob(["testdata/**"]),
embed = [":go_default_library"],
deps = [
"//async/event:go_default_library",

View File

@ -0,0 +1,2 @@
go test fuzz v1
string("0 ")

View File

@ -34,6 +34,11 @@ const (
mnemonicPassphrasePromptText = "(Advanced) Enter the '25th word' passphrase for your mnemonic"
)
var (
ErrIncorrectWordNumber = errors.New("incorrect number of words provided")
ErrEmptyMnemonic = errors.New("phrase cannot be empty")
)
// RecoverWalletConfig to run the recover wallet function.
type RecoverWalletConfig struct {
WalletDir string
@ -228,16 +233,18 @@ func inputNumAccounts(cliCtx *cli.Context) (int64, error) {
// as specified(currently 24).
func ValidateMnemonic(mnemonic string) error {
if strings.Trim(mnemonic, " ") == "" {
return errors.New("phrase cannot be empty")
return ErrEmptyMnemonic
}
words := strings.Split(mnemonic, " ")
for i, word := range words {
validWordCount := 0
for _, word := range words {
if strings.Trim(word, " ") == "" {
words = append(words[:i], words[i+1:]...)
continue
}
validWordCount += 1
}
if len(words) != phraseWordCount {
return fmt.Errorf("phrase must be %d words, entered %d", phraseWordCount, len(words))
if validWordCount != phraseWordCount {
return errors.Wrapf(ErrIncorrectWordNumber, "phrase must be %d words, entered %d", phraseWordCount, validWordCount)
}
return nil
}

View File

@ -0,0 +1,19 @@
//go:build go1.18
// +build go1.18
package accounts_test
import (
"testing"
"github.com/prysmaticlabs/prysm/validator/accounts"
)
func FuzzValidateMnemonic(f *testing.F) {
f.Add("bag wagon luxury iron swarm yellow course merge trumpet wide decide cash idea disagree deny teach canvas profit slice beach iron sting warfare slide")
f.Add("bag wagon luxury iron swarm yellow course merge trumpet wide cash idea disagree deny teach canvas profit iron sting warfare slide")
f.Add("bag wagon luxury iron swarm yellow course merge trumpet cash wide decide profit cash idea disagree deny teach canvas profit slice beach iron sting warfare slide")
f.Fuzz(func(t *testing.T, input string) {
accounts.ValidateMnemonic(input)
})
}

View File

@ -9,6 +9,7 @@ import (
"strconv"
"testing"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/cmd/validator/flags"
"github.com/prysmaticlabs/prysm/testing/assert"
"github.com/prysmaticlabs/prysm/testing/require"
@ -106,3 +107,56 @@ func TestRecoverDerivedWallet_AlreadyExists(t *testing.T) {
// Trying to recover an HD wallet into a directory that already exists should give an error
require.ErrorContains(t, "a wallet already exists at this location", RecoverWalletCli(cliCtx))
}
func TestValidateMnemonic(t *testing.T) {
tests := []struct {
name string
mnemonic string
wantErr bool
err error
}{
{
name: "Valid Mnemonic",
mnemonic: "bag wagon luxury iron swarm yellow course merge trumpet wide decide cash idea disagree deny teach canvas profit slice beach iron sting warfare slide",
wantErr: false,
},
{
name: "Invalid Mnemonic with too few words",
mnemonic: "bag wagon luxury iron swarm yellow course merge trumpet wide cash idea disagree deny teach canvas profit iron sting warfare slide",
wantErr: true,
err: ErrIncorrectWordNumber,
},
{
name: "Invalid Mnemonic with too many words",
mnemonic: "bag wagon luxury iron swarm yellow course merge trumpet cash wide decide profit cash idea disagree deny teach canvas profit slice beach iron sting warfare slide",
wantErr: true,
err: ErrIncorrectWordNumber,
},
{
name: "Empty Mnemonic",
mnemonic: "",
wantErr: true,
err: ErrEmptyMnemonic,
},
{
name: "Junk Mnemonic",
mnemonic: " a ",
wantErr: true,
err: ErrIncorrectWordNumber,
},
{
name: "Junk Mnemonic ",
mnemonic: " evilpacket ",
wantErr: true,
err: ErrIncorrectWordNumber,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateMnemonic(tt.mnemonic)
if (err != nil) != tt.wantErr || (tt.wantErr && !errors.Is(err, tt.err)) {
t.Errorf("ValidateMnemonic() error = %v, wantErr %v", err, tt.err)
}
})
}
}