Skip to content

Commit

Permalink
feat: add contribs/gnokeykc (#1270)
Browse files Browse the repository at this point in the history
## Done

- add a `contribs/gnokeykc` wrapper (adding keychain support).
- make `tm2/commands.IO` an interface instead of a struct.

## Usage

```console
$ gnokeykc kc set
Enter password.
Successfully added password for key.
$ gnokeykc maketx send --send 1ugnot --to g1fsu3z335h5qngf7t3lmakvpmpwg9ae76tqwh7c --chainid test3 --remote test3.gno.land:36657 --gas-fee "1000000ugnot" --gas-wanted "2000000" --broadcast moul


OK!
GAS WANTED: 2000000
GAS USED:   47072
```

## Links

- [x] Depends on #1256 (for contribs/' Makefile & CI)

---------

Signed-off-by: moul <[email protected]>
  • Loading branch information
moul authored Nov 9, 2023
1 parent da05213 commit 39ea662
Show file tree
Hide file tree
Showing 48 changed files with 582 additions and 124 deletions.
16 changes: 16 additions & 0 deletions contribs/gnokeykc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# `gnokeykc`

`gnokeykc` is a Go-based CLI tool that enhances [`gnokey`](../../gno.land/cmd/gnokey) by integrating with your system's keychain. It adds `gnokey kc ...` subcommands to set and unset passwords in the keychain, allowing Gnokey to fetch passwords directly from the keychain instead of prompting for terminal input.

## Usage

gnokey kc -h

## Terminal Alias

For ease of use, set up a terminal alias to replace `gnokey` with `gnokeykc`:

echo "alias gnokey='gnokeykc'" >> ~/.bashrc && source ~/.bashrc

Now, `gnokey` commands will use `gnokeykc`, fetching passwords from the keychain.

54 changes: 54 additions & 0 deletions contribs/gnokeykc/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module github.com/gnolang/gno/contribs/gnokeykc

go 1.20

replace github.com/gnolang/gno => ../..

require (
github.com/gnolang/gno v0.0.0-00010101000000-000000000000
github.com/zalando/go-keyring v0.2.3
)

require (
github.com/alessio/shellescape v1.4.1 // indirect
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c // indirect
github.com/btcsuite/btcd/btcutil v1.0.0 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/cockroachdb/apd v1.1.0 // indirect
github.com/danieljoos/wincred v1.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgraph-io/badger/v3 v3.2103.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/gnolang/goleveldb v0.0.9 // indirect
github.com/gnolang/overflow v0.0.0-20170615021017-4d914c927216 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.12.3 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/linxGnu/grocksdb v1.8.4 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/peterbourgon/ff/v3 v3.4.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rs/cors v1.10.1 // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
go.etcd.io/bbolt v1.3.7 // indirect
go.opencensus.io v0.22.5 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/tools v0.13.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
)
237 changes: 237 additions & 0 deletions contribs/gnokeykc/go.sum

Large diffs are not rendered by default.

94 changes: 94 additions & 0 deletions contribs/gnokeykc/kc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package main

import (
"context"
"flag"
"fmt"

"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/zalando/go-keyring"
)

const (
kcService = "gnokey"
kcName = "encryption"
)

func newKcCmd(io commands.IO) *commands.Command {
cmd := commands.NewCommand(
commands.Metadata{
Name: "kc",
ShortUsage: "kc <command>",
ShortHelp: "Manage OS keychain",
},
commands.NewEmptyConfig(),
commands.HelpExec,
)
cmd.AddSubCommands(
newKcSetCmd(io),
newKcUnsetCmd(io),
)
return cmd
}

func newKcSetCmd(io commands.IO) *commands.Command {
return commands.NewCommand(
commands.Metadata{
Name: "set",
ShortUsage: "set",
ShortHelp: "set encryption password in OS keychain",
},
commands.NewEmptyConfig(),
func(_ context.Context, args []string) error {
return execKcSet(args, io)
},
)
}

func execKcSet(args []string, io commands.IO) error {
if len(args) != 0 {
return flag.ErrHelp
}

insecurePasswordStdin := false // XXX: cfg.rootCfg.InsecurePasswordStdin
password, err := io.GetPassword("Enter password.", insecurePasswordStdin)
if err != nil {
return fmt.Errorf("cannot read password: %w", err)
}

err = keyring.Set(kcService, kcName, password)
if err != nil {
return fmt.Errorf("cannot set password is OS keychain")
}

io.Printfln("Successfully added password for key.")
return nil
}

func newKcUnsetCmd(io commands.IO) *commands.Command {
return commands.NewCommand(
commands.Metadata{
Name: "unset",
ShortUsage: "unset",
ShortHelp: "unset password in OS keychain",
},
commands.NewEmptyConfig(),
func(_ context.Context, args []string) error {
return execKcUnset(args, io)
},
)
}

func execKcUnset(args []string, io commands.IO) error {
if len(args) != 0 {
return flag.ErrHelp
}

err := keyring.Delete(kcService, kcName)
if err != nil {
return fmt.Errorf("cannot unset password from OS keychain")
}

io.Printfln("Successfully unset password")
return nil
}
32 changes: 32 additions & 0 deletions contribs/gnokeykc/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package main

import (
"context"
"fmt"
"os"

"github.com/gnolang/gno/tm2/pkg/commands"
"github.com/gnolang/gno/tm2/pkg/crypto/keys/client"
"github.com/zalando/go-keyring"
)

func main() {
stdio := commands.NewDefaultIO()
wrappedio := &wrappedIO{IO: stdio}
cmd := client.NewRootCmd(wrappedio)
cmd.AddSubCommands(newKcCmd(stdio))

if err := cmd.ParseAndRun(context.Background(), os.Args[1:]); err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%+v\n", err)

os.Exit(1)
}
}

type wrappedIO struct {
commands.IO
}

func (io *wrappedIO) GetPassword(prompt string, insecure bool) (string, error) {
return keyring.Get(kcService, kcName)
}
2 changes: 1 addition & 1 deletion gno.land/cmd/genesis/balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type balancesCfg struct {
}

// newBalancesCmd creates the genesis balances subcommand
func newBalancesCmd(io *commands.IO) *commands.Command {
func newBalancesCmd(io commands.IO) *commands.Command {
cfg := &balancesCfg{}

cmd := commands.NewCommand(
Expand Down
6 changes: 3 additions & 3 deletions gno.land/cmd/genesis/balances_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type balancesAddCfg struct {
}

// newBalancesAddCmd creates the genesis balances add subcommand
func newBalancesAddCmd(rootCfg *balancesCfg, io *commands.IO) *commands.Command {
func newBalancesAddCmd(rootCfg *balancesCfg, io commands.IO) *commands.Command {
cfg := &balancesAddCfg{
rootCfg: rootCfg,
}
Expand Down Expand Up @@ -75,7 +75,7 @@ func (c *balancesAddCfg) RegisterFlags(fs *flag.FlagSet) {
)
}

func execBalancesAdd(ctx context.Context, cfg *balancesAddCfg, io *commands.IO) error {
func execBalancesAdd(ctx context.Context, cfg *balancesAddCfg, io commands.IO) error {
// Load the genesis
genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.genesisPath)
if loadErr != nil {
Expand Down Expand Up @@ -232,7 +232,7 @@ func getBalancesFromSheet(sheet io.Reader) (accountBalances, error) {
// and construct a balance sheet based off of this information
func getBalancesFromTransactions(
ctx context.Context,
io *commands.IO,
io commands.IO,
reader io.Reader,
) (accountBalances, error) {
balances := make(accountBalances)
Expand Down
4 changes: 2 additions & 2 deletions gno.land/cmd/genesis/balances_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

// newBalancesExportCmd creates the genesis balances export subcommand
func newBalancesExportCmd(balancesCfg *balancesCfg, io *commands.IO) *commands.Command {
func newBalancesExportCmd(balancesCfg *balancesCfg, io commands.IO) *commands.Command {
return commands.NewCommand(
commands.Metadata{
Name: "export",
Expand All @@ -26,7 +26,7 @@ func newBalancesExportCmd(balancesCfg *balancesCfg, io *commands.IO) *commands.C
)
}

func execBalancesExport(cfg *balancesCfg, io *commands.IO, args []string) error {
func execBalancesExport(cfg *balancesCfg, io commands.IO, args []string) error {
// Load the genesis
genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath)
if loadErr != nil {
Expand Down
4 changes: 2 additions & 2 deletions gno.land/cmd/genesis/balances_remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type balancesRemoveCfg struct {
}

// newBalancesRemoveCmd creates the genesis balances remove subcommand
func newBalancesRemoveCmd(rootCfg *balancesCfg, io *commands.IO) *commands.Command {
func newBalancesRemoveCmd(rootCfg *balancesCfg, io commands.IO) *commands.Command {
cfg := &balancesRemoveCfg{
rootCfg: rootCfg,
}
Expand All @@ -51,7 +51,7 @@ func (c *balancesRemoveCfg) RegisterFlags(fs *flag.FlagSet) {
)
}

func execBalancesRemove(cfg *balancesRemoveCfg, io *commands.IO) error {
func execBalancesRemove(cfg *balancesRemoveCfg, io commands.IO) error {
// Load the genesis
genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.genesisPath)
if loadErr != nil {
Expand Down
4 changes: 2 additions & 2 deletions gno.land/cmd/genesis/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type generateCfg struct {
}

// newGenerateCmd creates the genesis generate subcommand
func newGenerateCmd(io *commands.IO) *commands.Command {
func newGenerateCmd(io commands.IO) *commands.Command {
cfg := &generateCfg{}

return commands.NewCommand(
Expand Down Expand Up @@ -91,7 +91,7 @@ func (c *generateCfg) RegisterFlags(fs *flag.FlagSet) {
)
}

func execGenerate(cfg *generateCfg, io *commands.IO) error {
func execGenerate(cfg *generateCfg, io commands.IO) error {
// Start with the default configuration
genesis := getDefaultGenesis()

Expand Down
2 changes: 1 addition & 1 deletion gno.land/cmd/genesis/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func main() {
}
}

func newRootCmd(io *commands.IO) *commands.Command {
func newRootCmd(io commands.IO) *commands.Command {
cmd := commands.NewCommand(
commands.Metadata{
ShortUsage: "<subcommand> [flags] [<arg>...]",
Expand Down
2 changes: 1 addition & 1 deletion gno.land/cmd/genesis/txs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type txsCfg struct {
}

// newTxsCmd creates the genesis txs subcommand
func newTxsCmd(io *commands.IO) *commands.Command {
func newTxsCmd(io commands.IO) *commands.Command {
cfg := &txsCfg{}

cmd := commands.NewCommand(
Expand Down
4 changes: 2 additions & 2 deletions gno.land/cmd/genesis/txs_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var (
)

// newTxsAddCmd creates the genesis txs add subcommand
func newTxsAddCmd(txsCfg *txsCfg, io *commands.IO) *commands.Command {
func newTxsAddCmd(txsCfg *txsCfg, io commands.IO) *commands.Command {
return commands.NewCommand(
commands.Metadata{
Name: "add",
Expand All @@ -40,7 +40,7 @@ func newTxsAddCmd(txsCfg *txsCfg, io *commands.IO) *commands.Command {
func execTxsAdd(
ctx context.Context,
cfg *txsCfg,
io *commands.IO,
io commands.IO,
args []string,
) error {
// Load the genesis
Expand Down
4 changes: 2 additions & 2 deletions gno.land/cmd/genesis/txs_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
var errNoOutputFile = errors.New("no output file path specified")

// newTxsExportCmd creates the genesis txs export subcommand
func newTxsExportCmd(txsCfg *txsCfg, io *commands.IO) *commands.Command {
func newTxsExportCmd(txsCfg *txsCfg, io commands.IO) *commands.Command {
return commands.NewCommand(
commands.Metadata{
Name: "export",
Expand All @@ -30,7 +30,7 @@ func newTxsExportCmd(txsCfg *txsCfg, io *commands.IO) *commands.Command {
)
}

func execTxsExport(cfg *txsCfg, io *commands.IO, args []string) error {
func execTxsExport(cfg *txsCfg, io commands.IO, args []string) error {
// Load the genesis
genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath)
if loadErr != nil {
Expand Down
4 changes: 2 additions & 2 deletions gno.land/cmd/genesis/txs_remove.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var (
)

// newTxsRemoveCmd creates the genesis txs remove subcommand
func newTxsRemoveCmd(txsCfg *txsCfg, io *commands.IO) *commands.Command {
func newTxsRemoveCmd(txsCfg *txsCfg, io commands.IO) *commands.Command {
return commands.NewCommand(
commands.Metadata{
Name: "remove",
Expand All @@ -35,7 +35,7 @@ func newTxsRemoveCmd(txsCfg *txsCfg, io *commands.IO) *commands.Command {
)
}

func execTxsRemove(cfg *txsCfg, io *commands.IO, args []string) error {
func execTxsRemove(cfg *txsCfg, io commands.IO, args []string) error {
// Load the genesis
genesis, loadErr := types.GenesisDocFromFile(cfg.genesisPath)
if loadErr != nil {
Expand Down
2 changes: 1 addition & 1 deletion gno.land/cmd/genesis/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type validatorCfg struct {
}

// newValidatorCmd creates the genesis validator subcommand
func newValidatorCmd(io *commands.IO) *commands.Command {
func newValidatorCmd(io commands.IO) *commands.Command {
cfg := &validatorCfg{
commonCfg: commonCfg{},
}
Expand Down
4 changes: 2 additions & 2 deletions gno.land/cmd/genesis/validator_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ type validatorAddCfg struct {
}

// newValidatorAddCmd creates the genesis validator add subcommand
func newValidatorAddCmd(validatorCfg *validatorCfg, io *commands.IO) *commands.Command {
func newValidatorAddCmd(validatorCfg *validatorCfg, io commands.IO) *commands.Command {
cfg := &validatorAddCfg{
rootCfg: validatorCfg,
}
Expand Down Expand Up @@ -69,7 +69,7 @@ func (c *validatorAddCfg) RegisterFlags(fs *flag.FlagSet) {
)
}

func execValidatorAdd(cfg *validatorAddCfg, io *commands.IO) error {
func execValidatorAdd(cfg *validatorAddCfg, io commands.IO) error {
// Load the genesis
genesis, loadErr := types.GenesisDocFromFile(cfg.rootCfg.genesisPath)
if loadErr != nil {
Expand Down
Loading

0 comments on commit 39ea662

Please sign in to comment.