Skip to content

Commit

Permalink
Merge PR #2441: Add swagger-ui for key management
Browse files Browse the repository at this point in the history
  • Loading branch information
cwgoes authored Oct 9, 2018
2 parents d6be4fc + 1aebe10 commit 7c9048b
Show file tree
Hide file tree
Showing 13 changed files with 497 additions and 156 deletions.
2 changes: 1 addition & 1 deletion PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ FEATURES
* [gaia-lite] [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add support for `generate_only=true` query argument to generate offline unsigned transactions
* [gaia-lite] [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) Add /sign endpoint to sign transactions generated with `generate_only=true`.
* [gaia-lite] [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) Add /broadcast endpoint to broadcast transactions signed by the /sign endpoint.
* [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`
* [gaia-lite] [\#2113](https://github.com/cosmos/cosmos-sdk/issues/2113) Rename `/accounts/{address}/send` to `/bank/accounts/{address}/transfers`, rename `/accounts/{address}` to `/auth/accounts/{address}`

* Gaia CLI (`gaiacli`)
* [cli] Cmds to query staking pool and params
Expand Down
212 changes: 148 additions & 64 deletions client/keys/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/cosmos/cosmos-sdk/client"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"

Expand Down Expand Up @@ -61,7 +60,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
name = "inmemorykey"
} else {
if len(args) != 1 || len(args[0]) == 0 {
return errors.New("you must provide a name for the key")
return errMissingName()
}
name = args[0]
kb, err = GetKeyBase()
Expand Down Expand Up @@ -144,11 +143,16 @@ func printCreate(info keys.Info, seed string) {
if !viper.GetBool(flagNoBackup) {
out.Seed = seed
}
json, err := MarshalJSON(out)
var jsonString []byte
if viper.GetBool(client.FlagIndentResponse) {
jsonString, err = cdc.MarshalJSONIndent(out, "", " ")
} else {
jsonString, err = cdc.MarshalJSON(out)
}
if err != nil {
panic(err) // really shouldn't happen...
}
fmt.Println(string(json))
fmt.Println(string(jsonString))
default:
panic(fmt.Sprintf("I can't speak: %s", output))
}
Expand All @@ -165,77 +169,78 @@ type NewKeyBody struct {
}

// add new key REST handler
func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
var kb keys.Keybase
var m NewKeyBody
func AddNewKeyRequestHandler(indent bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var kb keys.Keybase
var m NewKeyBody

kb, err := GetKeyBase()
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
kb, err := GetKeyBase()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}

body, err := ioutil.ReadAll(r.Body)
err = json.Unmarshal(body, &m)
body, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
err = json.Unmarshal(body, &m)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
if m.Name == "" {
w.WriteHeader(http.StatusBadRequest)
err = errMissingName()
w.Write([]byte(err.Error()))
return
}
if m.Password == "" {
w.WriteHeader(http.StatusBadRequest)
err = errMissingPassword()
w.Write([]byte(err.Error()))
return
}

if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
if m.Name == "" {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("You have to specify a name for the locally stored account."))
return
}
if m.Password == "" {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("You have to specify a password for the locally stored account."))
return
}
// check if already exists
infos, err := kb.List()
for _, info := range infos {
if info.GetName() == m.Name {
w.WriteHeader(http.StatusConflict)
err = errKeyNameConflict(m.Name)
w.Write([]byte(err.Error()))
return
}
}

// check if already exists
infos, err := kb.List()
for _, i := range infos {
if i.GetName() == m.Name {
w.WriteHeader(http.StatusConflict)
w.Write([]byte(fmt.Sprintf("Account with name %s already exists.", m.Name)))
// create account
seed := m.Seed
if seed == "" {
seed = getSeed(keys.Secp256k1)
}
info, err := kb.CreateKey(m.Name, seed, m.Password)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
}

// create account
seed := m.Seed
if seed == "" {
seed = getSeed(keys.Secp256k1)
}
info, err := kb.CreateKey(m.Name, seed, m.Password)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}

keyOutput, err := Bech32KeyOutput(info)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
keyOutput, err := Bech32KeyOutput(info)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}

keyOutput.Seed = seed
keyOutput.Seed = seed

bz, err := json.Marshal(keyOutput)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
PostProcessResponse(w, cdc, keyOutput, indent)
}

w.Write(bz)
}

// function to just a new seed to display in the UI before actually persisting it in the keybase
func getSeed(algo keys.SigningAlgo) string {
kb := client.MockKeyBase()
Expand All @@ -258,3 +263,82 @@ func SeedRequestHandler(w http.ResponseWriter, r *http.Request) {
seed := getSeed(algo)
w.Write([]byte(seed))
}

// RecoverKeyBody is recover key request REST body
type RecoverKeyBody struct {
Password string `json:"password"`
Seed string `json:"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 RecoverKeyBody
body, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
err = cdc.UnmarshalJSON(body, &m)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}

if name == "" {
w.WriteHeader(http.StatusBadRequest)
err = errMissingName()
w.Write([]byte(err.Error()))
return
}
if m.Password == "" {
w.WriteHeader(http.StatusBadRequest)
err = errMissingPassword()
w.Write([]byte(err.Error()))
return
}
if m.Seed == "" {
w.WriteHeader(http.StatusBadRequest)
err = errMissingSeed()
w.Write([]byte(err.Error()))
return
}

kb, err := GetKeyBase()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
// check if already exists
infos, err := kb.List()
for _, info := range infos {
if info.GetName() == name {
w.WriteHeader(http.StatusConflict)
err = errKeyNameConflict(name)
w.Write([]byte(err.Error()))
return
}
}

info, err := kb.CreateKey(name, m.Seed, m.Password)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}

keyOutput, err := Bech32KeyOutput(info)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}

PostProcessResponse(w, cdc, keyOutput, indent)
}
}
8 changes: 4 additions & 4 deletions client/keys/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,25 @@ func DeleteKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&m)
if err != nil {
w.WriteHeader(400)
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}

kb, err = GetKeyBase()
if err != nil {
w.WriteHeader(500)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}

// TODO handle error if key is not available or pass is wrong
err = kb.Delete(name, m.Password)
if err != nil {
w.WriteHeader(500)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}

w.WriteHeader(200)
w.WriteHeader(http.StatusOK)
}
19 changes: 19 additions & 0 deletions client/keys/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package keys

import "fmt"

func errKeyNameConflict(name string) error {
return fmt.Errorf("acount with name %s already exists", name)
}

func errMissingName() error {
return fmt.Errorf("you have to specify a name for the locally stored account")
}

func errMissingPassword() error {
return fmt.Errorf("you have to specify a password for the locally stored account")
}

func errMissingSeed() error {
return fmt.Errorf("you have to specify seed for key recover")
}
57 changes: 26 additions & 31 deletions client/keys/list.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package keys

import (
"encoding/json"
"net/http"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -35,35 +34,31 @@ func runListCmd(cmd *cobra.Command, args []string) error {
// REST

// query key list REST handler
func QueryKeysRequestHandler(w http.ResponseWriter, r *http.Request) {
kb, err := GetKeyBase()
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
infos, err := kb.List()
if err != nil {
w.WriteHeader(500)
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 {
w.Write([]byte("[]"))
return
}
keysOutput, err := Bech32KeysOutput(infos)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
output, err := json.MarshalIndent(keysOutput, "", " ")
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
func QueryKeysRequestHandler(indent bool) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
kb, err := GetKeyBase()
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 {
PostProcessResponse(w, cdc, "[]", indent)
return
}
keysOutput, err := Bech32KeysOutput(infos)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
PostProcessResponse(w, cdc, keysOutput, indent)
}
w.Write(output)
}
Loading

0 comments on commit 7c9048b

Please sign in to comment.