Merge pull request #3914 from filecoin-project/feat/lotus-shed-more
Add keyinfo verify and jwt token command to lotus-shed
This commit is contained in:
commit
0dfd4f3e63
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
@ -8,10 +9,12 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gbrlsnchs/jwt/v3"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||
"github.com/filecoin-project/lotus/api/apistruct"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
@ -24,6 +27,102 @@ var jwtCmd = &cli.Command{
|
||||
having to run the lotus daemon.`,
|
||||
Subcommands: []*cli.Command{
|
||||
jwtNewCmd,
|
||||
jwtTokenCmd,
|
||||
},
|
||||
}
|
||||
|
||||
var jwtTokenCmd = &cli.Command{
|
||||
Name: "token",
|
||||
Usage: "create a token for a given jwt secret",
|
||||
ArgsUsage: "<name>",
|
||||
Description: `The jwt tokens have four different levels of permissions that provide some ability
|
||||
to control access to what methods can be invoked by the holder of the token.
|
||||
|
||||
This command only works on jwt secrets that are base16 encoded files, such as those produced by the
|
||||
sibling 'new' command.
|
||||
`,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "output",
|
||||
Value: "token",
|
||||
Usage: "specify a name",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "read",
|
||||
Value: false,
|
||||
Usage: "add read permissions to the token",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "write",
|
||||
Value: false,
|
||||
Usage: "add write permissions to the token",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "sign",
|
||||
Value: false,
|
||||
Usage: "add sign permissions to the token",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "admin",
|
||||
Value: false,
|
||||
Usage: "add admin permissions to the token",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
if !cctx.Args().Present() {
|
||||
return fmt.Errorf("please specify a name")
|
||||
}
|
||||
|
||||
inputFile, err := os.Open(cctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer inputFile.Close() //nolint:errcheck
|
||||
input := bufio.NewReader(inputFile)
|
||||
|
||||
encoded, err := ioutil.ReadAll(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
decoded, err := hex.DecodeString(strings.TrimSpace(string(encoded)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var keyInfo types.KeyInfo
|
||||
if err := json.Unmarshal(decoded, &keyInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
perms := []auth.Permission{}
|
||||
|
||||
if cctx.Bool("read") {
|
||||
perms = append(perms, apistruct.PermRead)
|
||||
}
|
||||
|
||||
if cctx.Bool("write") {
|
||||
perms = append(perms, apistruct.PermWrite)
|
||||
}
|
||||
|
||||
if cctx.Bool("sign") {
|
||||
perms = append(perms, apistruct.PermSign)
|
||||
}
|
||||
|
||||
if cctx.Bool("admin") {
|
||||
perms = append(perms, apistruct.PermAdmin)
|
||||
}
|
||||
|
||||
p := modules.JwtPayload{
|
||||
Allow: perms,
|
||||
}
|
||||
|
||||
token, err := jwt.Sign(&p, jwt.NewHS256(keyInfo.PrivateKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(cctx.String("output"), token, 0600)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -9,16 +9,22 @@ import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/multiformats/go-base32"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
"github.com/filecoin-project/lotus/node/modules/lp2p"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
|
||||
@ -43,6 +49,90 @@ var keyinfoCmd = &cli.Command{
|
||||
keyinfoNewCmd,
|
||||
keyinfoInfoCmd,
|
||||
keyinfoImportCmd,
|
||||
keyinfoVerifyCmd,
|
||||
},
|
||||
}
|
||||
|
||||
var keyinfoVerifyCmd = &cli.Command{
|
||||
Name: "verify",
|
||||
Usage: "verify the filename of a keystore object on disk with it's contents",
|
||||
Description: `Keystore objects are base32 enocded strings, with wallets being dynamically named via
|
||||
the wallet address. This command can ensure that the naming of these keystore objects are correct`,
|
||||
Action: func(cctx *cli.Context) error {
|
||||
filePath := cctx.Args().First()
|
||||
fileName := path.Base(filePath)
|
||||
|
||||
inputFile, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer inputFile.Close() //nolint:errcheck
|
||||
input := bufio.NewReader(inputFile)
|
||||
|
||||
keyContent, err := ioutil.ReadAll(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var keyInfo types.KeyInfo
|
||||
if err := json.Unmarshal(keyContent, &keyInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch keyInfo.Type {
|
||||
case lp2p.KTLibp2pHost:
|
||||
name, err := base32.RawStdEncoding.DecodeString(fileName)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("decoding key: '%s': %w", fileName, err)
|
||||
}
|
||||
|
||||
if string(name) != keyInfo.Type {
|
||||
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
|
||||
}
|
||||
case modules.KTJwtHmacSecret:
|
||||
name, err := base32.RawStdEncoding.DecodeString(fileName)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("decoding key: '%s': %w", fileName, err)
|
||||
}
|
||||
|
||||
if string(name) != modules.JWTSecretName {
|
||||
return fmt.Errorf("%s of type %s is incorrect", fileName, keyInfo.Type)
|
||||
}
|
||||
case wallet.KTSecp256k1, wallet.KTBLS:
|
||||
keystore := wallet.NewMemKeyStore()
|
||||
w, err := wallet.NewWallet(keystore)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := w.Import(&keyInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
list, err := keystore.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(list) != 1 {
|
||||
return fmt.Errorf("Unexpected number of keys, expected 1, found %d", len(list))
|
||||
}
|
||||
|
||||
name, err := base32.RawStdEncoding.DecodeString(fileName)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("decoding key: '%s': %w", fileName, err)
|
||||
}
|
||||
|
||||
if string(name) != list[0] {
|
||||
return fmt.Errorf("%s of type %s; file is named for %s, but key is actually %s", fileName, keyInfo.Type, string(name), list[0])
|
||||
}
|
||||
|
||||
break
|
||||
default:
|
||||
return fmt.Errorf("Unknown keytype %s", keyInfo.Type)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user