Skip to content

Commit

Permalink
Merge PR #3674: Remove password/keybase from REST Client
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez authored and jackzampolin committed Feb 19, 2019
1 parent 6967de1 commit e39debd
Show file tree
Hide file tree
Showing 26 changed files with 324 additions and 1,324 deletions.
5 changes: 5 additions & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

### Gaia REST API

* [\#3641] Remove the ability to use a Keybase from the REST API client:
* `password` and `generate_only` have been removed from the `base_req` object
* All txs that used to sign or use the Keybase now only generate the tx
* `keys` routes completely removed

### Gaia CLI

### Gaia
Expand Down
195 changes: 1 addition & 194 deletions client/keys/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,21 @@ package keys

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"sort"

"github.com/cosmos/cosmos-sdk/client"
"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"
Expand Down Expand Up @@ -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 changes: 0 additions & 40 deletions client/keys/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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 changes: 0 additions & 53 deletions client/keys/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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)
}
Loading

0 comments on commit e39debd

Please sign in to comment.