Merge PR #3674: Remove password/keybase from REST Client

This commit is contained in:
Alexander Bezobchuk
2019-02-19 10:15:39 -08:00
committed by Jack Zampolin
parent 6967de1073
commit e39debd359
26 changed files with 335 additions and 1335 deletions
+1 -194
View File
@@ -2,10 +2,7 @@ package keys
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"sort"
@@ -13,15 +10,13 @@ import (
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/crypto/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
"errors"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/go-bip39"
bip39 "github.com/cosmos/go-bip39"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/multisig"
@@ -304,191 +299,3 @@ func printCreate(info keys.Info, showMnemonic bool, mnemonic string) error {
return nil
}
/////////////////////////////
// REST
// function to just create a new seed to display in the UI before actually persisting it in the keybase
func generateMnemonic(algo keys.SigningAlgo) string {
kb := keys.NewInMemory()
pass := app.DefaultKeyPass
name := "inmemorykey"
_, seed, _ := kb.CreateMnemonic(name, keys.English, pass, algo)
return seed
}
// CheckAndWriteErrorResponse will check for errors and return
// a given error message when corresponding
//TODO: Move to utils/rest or similar
func CheckAndWriteErrorResponse(w http.ResponseWriter, httpErr int, err error) bool {
if err != nil {
w.WriteHeader(httpErr)
_, _ = w.Write([]byte(err.Error()))
return true
}
return false
}
// add new key REST handler
func AddNewKeyRequestHandler(indent bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var kb keys.Keybase
var m AddNewKey
kb, err := NewKeyBaseFromHomeFlag()
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
return
}
body, err := ioutil.ReadAll(r.Body)
if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) {
return
}
err = json.Unmarshal(body, &m)
if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) {
return
}
// Check parameters
if m.Name == "" {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName())
return
}
if m.Password == "" {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword())
return
}
mnemonic := m.Mnemonic
// if mnemonic is empty, generate one
if mnemonic == "" {
mnemonic = generateMnemonic(keys.Secp256k1)
}
if !bip39.IsMnemonicValid(mnemonic) {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic())
}
if m.Account < 0 || m.Account > maxValidAccountValue {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber())
return
}
if m.Index < 0 || m.Index > maxValidIndexalue {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber())
return
}
_, err = kb.Get(m.Name)
if err == nil {
CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(m.Name))
return
}
// create account
account := uint32(m.Account)
index := uint32(m.Index)
info, err := kb.CreateAccount(m.Name, mnemonic, keys.DefaultBIP39Passphrase, m.Password, account, index)
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
return
}
keyOutput, err := Bech32KeyOutput(info)
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
return
}
keyOutput.Mnemonic = mnemonic
rest.PostProcessResponse(w, cdc, keyOutput, indent)
}
}
// Seed REST request handler
func SeedRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
algoType := vars["type"]
// algo type defaults to secp256k1
if algoType == "" {
algoType = "secp256k1"
}
algo := keys.SigningAlgo(algoType)
seed := generateMnemonic(algo)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(seed))
}
// RecoverRequestHandler performs key recover request
func RecoverRequestHandler(indent bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]
var m RecoverKey
body, err := ioutil.ReadAll(r.Body)
if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) {
return
}
err = cdc.UnmarshalJSON(body, &m)
if CheckAndWriteErrorResponse(w, http.StatusBadRequest, err) {
return
}
kb, err := NewKeyBaseFromHomeFlag()
CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err)
if name == "" {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingName())
return
}
if m.Password == "" {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingPassword())
return
}
mnemonic := m.Mnemonic
if !bip39.IsMnemonicValid(mnemonic) {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidMnemonic())
}
if m.Mnemonic == "" {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errMissingMnemonic())
return
}
if m.Account < 0 || m.Account > maxValidAccountValue {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidAccountNumber())
return
}
if m.Index < 0 || m.Index > maxValidIndexalue {
CheckAndWriteErrorResponse(w, http.StatusBadRequest, errInvalidIndexNumber())
return
}
_, err = kb.Get(name)
if err == nil {
CheckAndWriteErrorResponse(w, http.StatusConflict, errKeyNameConflict(name))
return
}
account := uint32(m.Account)
index := uint32(m.Index)
info, err := kb.CreateAccount(name, mnemonic, keys.DefaultBIP39Passphrase, m.Password, account, index)
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
return
}
keyOutput, err := Bech32KeyOutput(info)
if CheckAndWriteErrorResponse(w, http.StatusInternalServerError, err) {
return
}
rest.PostProcessResponse(w, cdc, keyOutput, indent)
}
}
-40
View File
@@ -2,13 +2,9 @@ package keys
import (
"bufio"
"net/http"
"strings"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/cli"
@@ -61,39 +57,3 @@ func Test_runAddCmdBasic(t *testing.T) {
err = runAddCmd(cmd, []string{"keyname2"})
assert.NoError(t, err)
}
type MockResponseWriter struct {
dataHeaderStatus int
dataBody []byte
}
func (MockResponseWriter) Header() http.Header {
panic("Unexpected call!")
}
func (w *MockResponseWriter) Write(data []byte) (int, error) {
w.dataBody = append(w.dataBody, data...)
return len(data), nil
}
func (w *MockResponseWriter) WriteHeader(statusCode int) {
w.dataHeaderStatus = statusCode
}
func TestCheckAndWriteErrorResponse(t *testing.T) {
mockRW := MockResponseWriter{}
mockRW.WriteHeader(100)
assert.Equal(t, 100, mockRW.dataHeaderStatus)
detected := CheckAndWriteErrorResponse(&mockRW, http.StatusBadRequest, errors.New("some ERROR"))
require.True(t, detected)
require.Equal(t, http.StatusBadRequest, mockRW.dataHeaderStatus)
require.Equal(t, "some ERROR", string(mockRW.dataBody[:]))
mockRW = MockResponseWriter{}
detected = CheckAndWriteErrorResponse(&mockRW, http.StatusBadRequest, nil)
require.False(t, detected)
require.Equal(t, 0, mockRW.dataHeaderStatus)
require.Equal(t, "", string(mockRW.dataBody[:]))
}
-53
View File
@@ -2,19 +2,14 @@ package keys
import (
"bufio"
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
"github.com/spf13/viper"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
"github.com/spf13/cobra"
)
@@ -101,51 +96,3 @@ func confirmDeletion(buf *bufio.Reader) error {
}
return nil
}
////////////////////////
// REST
// delete key request REST body
type DeleteKeyBody struct {
Password string `json:"password"`
}
// delete key REST handler
func DeleteKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]
var kb keys.Keybase
var m DeleteKeyBody
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&m)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(err.Error()))
return
}
kb, err = NewKeyBaseFromHomeFlag()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
err = kb.Delete(name, m.Password, false)
if keyerror.IsErrKeyNotFound(err) {
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(err.Error()))
return
} else if keyerror.IsErrWrongPassword(err) {
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte(err.Error()))
return
} else if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
w.WriteHeader(http.StatusOK)
}
-36
View File
@@ -1,9 +1,6 @@
package keys
import (
"net/http"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/spf13/cobra"
)
@@ -29,36 +26,3 @@ func runListCmd(cmd *cobra.Command, args []string) error {
}
return err
}
/////////////////////////
// REST
// query key list REST handler
func QueryKeysRequestHandler(indent bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
kb, err := NewKeyBaseFromHomeFlag()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
infos, err := kb.List()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
// an empty list will be JSONized as null, but we want to keep the empty list
if len(infos) == 0 {
rest.PostProcessResponse(w, cdc, []string{}, indent)
return
}
keysOutput, err := Bech32KeysOutput(infos)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
rest.PostProcessResponse(w, cdc, keysOutput, indent)
}
}
-12
View File
@@ -1,7 +1,6 @@
package keys
import (
"github.com/gorilla/mux"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
@@ -30,14 +29,3 @@ func Commands() *cobra.Command {
)
return cmd
}
// resgister REST routes
func RegisterRoutes(r *mux.Router, indent bool) {
r.HandleFunc("/keys", QueryKeysRequestHandler(indent)).Methods("GET")
r.HandleFunc("/keys", AddNewKeyRequestHandler(indent)).Methods("POST")
r.HandleFunc("/keys/seed", SeedRequestHandler).Methods("GET")
r.HandleFunc("/keys/{name}/recover", RecoverRequestHandler(indent)).Methods("POST")
r.HandleFunc("/keys/{name}", GetKeyRequestHandler(indent)).Methods("GET")
r.HandleFunc("/keys/{name}", UpdateKeyRequestHandler).Methods("PUT")
r.HandleFunc("/keys/{name}", DeleteKeyRequestHandler).Methods("DELETE")
}
-7
View File
@@ -4,8 +4,6 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/gorilla/mux"
)
func TestCommands(t *testing.T) {
@@ -15,8 +13,3 @@ func TestCommands(t *testing.T) {
// Commands are registered
assert.Equal(t, 7, len(rootCommands.Commands()))
}
func TestRegisterRoutes(t *testing.T) {
fakeRouter := mux.Router{}
RegisterRoutes(&fakeRouter, false)
}
-47
View File
@@ -2,22 +2,18 @@ package keys
import (
"fmt"
"net/http"
"github.com/tendermint/tendermint/crypto"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/types/rest"
"errors"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/crypto/multisig"
"github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@@ -149,46 +145,3 @@ func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) {
return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix)
}
///////////////////////////
// REST
// get key REST handler
func GetKeyRequestHandler(indent bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]
bechPrefix := r.URL.Query().Get(FlagBechPrefix)
if bechPrefix == "" {
bechPrefix = sdk.PrefixAccount
}
bechKeyOut, err := getBechKeyOut(bechPrefix)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(err.Error()))
return
}
info, err := GetKeyInfo(name)
if keyerror.IsErrKeyNotFound(err) {
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(err.Error()))
return
} else if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
keyOutput, err := bechKeyOut(info)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
rest.PostProcessResponse(w, cdc, keyOutput, indent)
}
}
-59
View File
@@ -1,18 +1,11 @@
package keys
import (
"encoding/json"
"fmt"
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/crypto/keys/keyerror"
)
func updateKeyCommand() *cobra.Command {
@@ -52,55 +45,3 @@ func runUpdateCmd(cmd *cobra.Command, args []string) error {
fmt.Println("Password successfully updated!")
return nil
}
///////////////////////
// REST
// update key request REST body
type UpdateKeyBody struct {
NewPassword string `json:"new_password"`
OldPassword string `json:"old_password"`
}
// update key REST handler
func UpdateKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]
var kb keys.Keybase
var m UpdateKeyBody
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&m)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte(err.Error()))
return
}
kb, err = NewKeyBaseFromHomeFlag()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
getNewpass := func() (string, error) { return m.NewPassword, nil }
err = kb.Update(name, m.OldPassword, getNewpass)
if keyerror.IsErrKeyNotFound(err) {
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(err.Error()))
return
} else if keyerror.IsErrWrongPassword(err) {
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte(err.Error()))
return
} else if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
}