diff --git a/cmd/kaspawallet/config.go b/cmd/kaspawallet/config.go index 8d97af97c..d9b38e60b 100644 --- a/cmd/kaspawallet/config.go +++ b/cmd/kaspawallet/config.go @@ -31,6 +31,8 @@ type configFlags struct { type createConfig struct { KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"` + Password string `long:"password" short:"p" description:"Wallet password"` + Yes bool `long:"yes" short:"y" description:"Assume \"yes\" to all questions"` MinimumSignatures uint32 `long:"min-signatures" short:"m" description:"Minimum required signatures" default:"1"` NumPrivateKeys uint32 `long:"num-private-keys" short:"k" description:"Number of private keys" default:"1"` NumPublicKeys uint32 `long:"num-public-keys" short:"n" description:"Total number of keys" default:"1"` @@ -46,6 +48,7 @@ type balanceConfig struct { type sendConfig struct { KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"` + Password string `long:"password" short:"p" description:"Wallet password"` DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to (default: localhost:8082)"` ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"` SendAmount float64 `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)" required:"true"` @@ -61,6 +64,7 @@ type createUnsignedTransactionConfig struct { type signConfig struct { KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"` + Password string `long:"password" short:"p" description:"Wallet password"` Transaction string `long:"transaction" short:"t" description:"The unsigned transaction to sign on (encoded in hex)" required:"true"` config.NetworkFlags } @@ -78,6 +82,7 @@ type showAddressConfig struct { type startDaemonConfig struct { KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"` + Password string `long:"password" short:"p" description:"Wallet password"` RPCServer string `long:"rpcserver" short:"s" description:"RPC server to connect to"` Listen string `short:"l" long:"listen" description:"Address to listen on (default: 0.0.0.0:8082)"` config.NetworkFlags @@ -85,6 +90,8 @@ type startDaemonConfig struct { type dumpUnencryptedDataConfig struct { KeysFile string `long:"keys-file" short:"f" description:"Keys file location (default: ~/.kaspawallet/keys.json (*nix), %USERPROFILE%\\AppData\\Local\\Kaspawallet\\key.json (Windows))"` + Password string `long:"password" short:"p" description:"Wallet password"` + Yes bool `long:"yes" short:"y" description:"Assume \"yes\" to all questions"` config.NetworkFlags } diff --git a/cmd/kaspawallet/create.go b/cmd/kaspawallet/create.go index 157562d37..3e8f5286f 100644 --- a/cmd/kaspawallet/create.go +++ b/cmd/kaspawallet/create.go @@ -18,9 +18,9 @@ func create(conf *createConfig) error { var err error isMultisig := conf.NumPublicKeys > 1 if !conf.Import { - encryptedMnemonics, signerExtendedPublicKeys, err = keys.CreateMnemonics(conf.NetParams(), conf.NumPrivateKeys, isMultisig) + encryptedMnemonics, signerExtendedPublicKeys, err = keys.CreateMnemonics(conf.NetParams(), conf.NumPrivateKeys, conf.Password, isMultisig) } else { - encryptedMnemonics, signerExtendedPublicKeys, err = keys.ImportMnemonics(conf.NetParams(), conf.NumPrivateKeys, isMultisig) + encryptedMnemonics, signerExtendedPublicKeys, err = keys.ImportMnemonics(conf.NetParams(), conf.NumPrivateKeys, conf.Password, isMultisig) } if err != nil { return err @@ -63,7 +63,7 @@ func create(conf *createConfig) error { ECDSA: conf.ECDSA, } - err = file.SetPath(conf.NetParams(), conf.KeysFile) + err = file.SetPath(conf.NetParams(), conf.KeysFile, conf.Yes) if err != nil { return err } diff --git a/cmd/kaspawallet/dump_unencrypted_data.go b/cmd/kaspawallet/dump_unencrypted_data.go index a8a762285..958decb43 100644 --- a/cmd/kaspawallet/dump_unencrypted_data.go +++ b/cmd/kaspawallet/dump_unencrypted_data.go @@ -12,9 +12,11 @@ import ( ) func dumpUnencryptedData(conf *dumpUnencryptedDataConfig) error { - err := confirmDump() - if err != nil { - return err + if !conf.Yes { + err := confirmDump() + if err != nil { + return err + } } keysFile, err := keys.ReadKeysFile(conf.NetParams(), conf.KeysFile) @@ -22,7 +24,7 @@ func dumpUnencryptedData(conf *dumpUnencryptedDataConfig) error { return err } - mnemonics, err := keysFile.DecryptMnemonics() + mnemonics, err := keysFile.DecryptMnemonics(conf.Password) if err != nil { return err } diff --git a/cmd/kaspawallet/keys/create.go b/cmd/kaspawallet/keys/create.go index 244011bf5..340a4a41b 100644 --- a/cmd/kaspawallet/keys/create.go +++ b/cmd/kaspawallet/keys/create.go @@ -14,7 +14,7 @@ import ( ) // CreateMnemonics generates `numKeys` number of mnemonics. -func CreateMnemonics(params *dagconfig.Params, numKeys uint32, isMultisig bool) (encryptedPrivateKeys []*EncryptedMnemonic, extendedPublicKeys []string, err error) { +func CreateMnemonics(params *dagconfig.Params, numKeys uint32, cmdLinePassword string, isMultisig bool) (encryptedPrivateKeys []*EncryptedMnemonic, extendedPublicKeys []string, err error) { mnemonics := make([]string, numKeys) for i := uint32(0); i < numKeys; i++ { var err error @@ -24,11 +24,11 @@ func CreateMnemonics(params *dagconfig.Params, numKeys uint32, isMultisig bool) } } - return encryptedMnemonicExtendedPublicKeyPairs(params, mnemonics, isMultisig) + return encryptedMnemonicExtendedPublicKeyPairs(params, mnemonics, cmdLinePassword, isMultisig) } // ImportMnemonics imports a `numKeys` of mnemonics. -func ImportMnemonics(params *dagconfig.Params, numKeys uint32, isMultisig bool) (encryptedPrivateKeys []*EncryptedMnemonic, extendedPublicKeys []string, err error) { +func ImportMnemonics(params *dagconfig.Params, numKeys uint32, cmdLinePassword string, isMultisig bool) (encryptedPrivateKeys []*EncryptedMnemonic, extendedPublicKeys []string, err error) { mnemonics := make([]string, numKeys) for i := uint32(0); i < numKeys; i++ { fmt.Printf("Enter mnemonic #%d here:\n", i+1) @@ -44,17 +44,20 @@ func ImportMnemonics(params *dagconfig.Params, numKeys uint32, isMultisig bool) mnemonics[i] = string(mnemonic) } - return encryptedMnemonicExtendedPublicKeyPairs(params, mnemonics, isMultisig) + return encryptedMnemonicExtendedPublicKeyPairs(params, mnemonics, cmdLinePassword, isMultisig) } -func encryptedMnemonicExtendedPublicKeyPairs(params *dagconfig.Params, mnemonics []string, isMultisig bool) ( +func encryptedMnemonicExtendedPublicKeyPairs(params *dagconfig.Params, mnemonics []string, cmdLinePassword string, isMultisig bool) ( encryptedPrivateKeys []*EncryptedMnemonic, extendedPublicKeys []string, err error) { + password := []byte(cmdLinePassword) + if len(password) == 0 { - password := getPassword("Enter password for the key file:") - confirmPassword := getPassword("Confirm password:") + password = getPassword("Enter password for the key file:") + confirmPassword := getPassword("Confirm password:") - if subtle.ConstantTimeCompare(password, confirmPassword) != 1 { - return nil, nil, errors.New("Passwords are not identical") + if subtle.ConstantTimeCompare(password, confirmPassword) != 1 { + return nil, nil, errors.New("Passwords are not identical") + } } encryptedPrivateKeys = make([]*EncryptedMnemonic, 0, len(mnemonics)) diff --git a/cmd/kaspawallet/keys/keys.go b/cmd/kaspawallet/keys/keys.go index 5bd508655..b88e81bda 100644 --- a/cmd/kaspawallet/keys/keys.go +++ b/cmd/kaspawallet/keys/keys.go @@ -109,29 +109,30 @@ func (d *File) fromJSON(fileJSON *keysFileJSON) error { } // SetPath sets the path where the file is saved to. -func (d *File) SetPath(params *dagconfig.Params, path string) error { +func (d *File) SetPath(params *dagconfig.Params, path string, forceOverride bool) error { if path == "" { path = defaultKeysFile(params) } - exists, err := pathExists(path) - if err != nil { - return err - } - - if exists { - reader := bufio.NewReader(os.Stdin) - fmt.Printf("The file %s already exists. Are you sure you want to override it (type 'y' to approve)? ", d.path) - line, err := utils.ReadLine(reader) + if !forceOverride { + exists, err := pathExists(path) if err != nil { return err } - if string(line) != "y" { - return errors.Errorf("aborted setting the file path to %s", path) + if exists { + reader := bufio.NewReader(os.Stdin) + fmt.Printf("The file %s already exists. Are you sure you want to override it (type 'y' to approve)? ", d.path) + line, err := utils.ReadLine(reader) + if err != nil { + return err + } + + if string(line) != "y" { + return errors.Errorf("aborted setting the file path to %s", path) + } } } - d.path = path return nil } @@ -175,8 +176,11 @@ func (d *File) LastUsedInternalIndex() uint32 { // DecryptMnemonics asks the user to enter the password for the private keys and // returns the decrypted private keys. -func (d *File) DecryptMnemonics() ([]string, error) { - password := getPassword("Password:") +func (d *File) DecryptMnemonics(cmdLinePassword string) ([]string, error) { + password := []byte(cmdLinePassword) + if len(password) == 0 { + password = getPassword("Password:") + } privateKeys := make([]string, len(d.EncryptedMnemonics)) for i, encryptedPrivateKey := range d.EncryptedMnemonics { var err error diff --git a/cmd/kaspawallet/send.go b/cmd/kaspawallet/send.go index 8ad2428b2..7b4fd339e 100644 --- a/cmd/kaspawallet/send.go +++ b/cmd/kaspawallet/send.go @@ -39,7 +39,7 @@ func send(conf *sendConfig) error { return err } - mnemonics, err := keysFile.DecryptMnemonics() + mnemonics, err := keysFile.DecryptMnemonics(conf.Password) if err != nil { return err } diff --git a/cmd/kaspawallet/sign.go b/cmd/kaspawallet/sign.go index 5c274da33..23ebfd0b5 100644 --- a/cmd/kaspawallet/sign.go +++ b/cmd/kaspawallet/sign.go @@ -18,7 +18,7 @@ func sign(conf *signConfig) error { return err } - privateKeys, err := keysFile.DecryptMnemonics() + privateKeys, err := keysFile.DecryptMnemonics(conf.Password) if err != nil { return err } diff --git a/go.mod b/go.mod index 314ee0975..d2cb2fc74 100644 --- a/go.mod +++ b/go.mod @@ -15,10 +15,10 @@ require ( github.com/pkg/errors v0.9.1 github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d github.com/tyler-smith/go-bip39 v1.1.0 - golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670 - golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 + golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a + golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea // indirect + golang.org/x/term v0.0.0-20210503060354-a79de5458b56 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect google.golang.org/grpc v1.33.1 - google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 // indirect google.golang.org/protobuf v1.26.0 ) diff --git a/go.sum b/go.sum index 0e4d65eea..93da88399 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,6 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -47,8 +45,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -79,8 +76,9 @@ golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670 h1:gzMM0EjIYiRmJI3+jBdFuoynZlpxa2JQZsolKu09BXo= golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -102,11 +100,12 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea h1:+WiDlPBBaO+h9vPNZi8uJ3k4BkKQB7Iow3aqwHVA5hI= +golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210317153231-de623e64d2a6 h1:EC6+IGYTjPpRfv9a2b/6Puw0W+hLtAhkV1tPsXhutqs= -golang.org/x/term v0.0.0-20210317153231-de623e64d2a6/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= +golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -129,18 +128,13 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=