From f1632376e7561d60e4c898bf32f6bca7a9095693 Mon Sep 17 00:00:00 2001 From: Travis Person Date: Wed, 19 Aug 2020 19:18:36 +0000 Subject: [PATCH] lotus-shed: add simple jwt creation support --- cmd/lotus-shed/jwt.go | 89 +++++++++++++++++++++++++++++++++++++++ cmd/lotus-shed/keyinfo.go | 2 +- cmd/lotus-shed/main.go | 1 + node/modules/core.go | 7 +-- 4 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 cmd/lotus-shed/jwt.go diff --git a/cmd/lotus-shed/jwt.go b/cmd/lotus-shed/jwt.go new file mode 100644 index 000000000..d37359f71 --- /dev/null +++ b/cmd/lotus-shed/jwt.go @@ -0,0 +1,89 @@ +package main + +import ( + "crypto/rand" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + + "github.com/gbrlsnchs/jwt/v3" + "github.com/urfave/cli/v2" + + "github.com/filecoin-project/lotus/api/apistruct" + "github.com/filecoin-project/lotus/chain/types" + "github.com/filecoin-project/lotus/node/modules" +) + +var jwtCmd = &cli.Command{ + Name: "jwt", + Usage: "work with lotus jwt secrets and tokens", + Description: `The subcommands of jwt provide helpful tools for working with jwt files without + having to run the lotus daemon.`, + Subcommands: []*cli.Command{ + jwtNewCmd, + }, +} + +var jwtNewCmd = &cli.Command{ + Name: "new", + Usage: "create a new jwt secret and token for lotus", + ArgsUsage: "", + Description: `Jwt tokens are used to authenticate api requests to the lotus daemon. + + The created jwt token have full privileges and should not be shared.`, + Flags: []cli.Flag{}, + Action: func(cctx *cli.Context) error { + if !cctx.Args().Present() { + return fmt.Errorf("please specify a name") + } + + keyName := cctx.Args().First() + + sk, err := ioutil.ReadAll(io.LimitReader(rand.Reader, 32)) + if err != nil { + return err + } + + keyInfo := types.KeyInfo{ + Type: modules.KTJwtHmacSecret, + PrivateKey: sk, + } + + p := modules.JwtPayload{ + Allow: apistruct.AllPermissions, + } + + token, err := jwt.Sign(&p, jwt.NewHS256(keyInfo.PrivateKey)) + if err != nil { + return err + } + + filename := fmt.Sprintf("jwt-%s.jwts", keyName) + file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return err + } + + defer func() { + if err := file.Close(); err != nil { + log.Warnf("failed to close output file: %w", err) + } + }() + + bytes, err := json.Marshal(keyInfo) + if err != nil { + return err + } + + encoded := hex.EncodeToString(bytes) + if _, err := file.Write([]byte(encoded)); err != nil { + return err + } + + filenameToken := fmt.Sprintf("jwt-%s.token", keyName) + return ioutil.WriteFile(filenameToken, token, 0600) + }, +} diff --git a/cmd/lotus-shed/keyinfo.go b/cmd/lotus-shed/keyinfo.go index 028ead413..0f608d858 100644 --- a/cmd/lotus-shed/keyinfo.go +++ b/cmd/lotus-shed/keyinfo.go @@ -325,7 +325,7 @@ var keyinfoNewCmd = &cli.Command{ filename = strings.ReplaceAll(filename, "", keyAddr) filename = strings.ReplaceAll(filename, "", keyType) - file, err := os.Create(filename) + file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { return err } diff --git a/cmd/lotus-shed/main.go b/cmd/lotus-shed/main.go index c37b93a42..4126fa649 100644 --- a/cmd/lotus-shed/main.go +++ b/cmd/lotus-shed/main.go @@ -19,6 +19,7 @@ func main() { base16Cmd, bitFieldCmd, keyinfoCmd, + jwtCmd, noncefix, bigIntParseCmd, staterootStatsCmd, diff --git a/node/modules/core.go b/node/modules/core.go index 84179bd63..1f21f2720 100644 --- a/node/modules/core.go +++ b/node/modules/core.go @@ -37,8 +37,9 @@ func RecordValidator(ps peerstore.Peerstore) record.Validator { } const JWTSecretName = "auth-jwt-private" //nolint:gosec +const KTJwtHmacSecret = "jwt-hmac-secret" -type jwtPayload struct { +type JwtPayload struct { Allow []auth.Permission } @@ -54,7 +55,7 @@ func APISecret(keystore types.KeyStore, lr repo.LockedRepo) (*dtypes.APIAlg, err } key = types.KeyInfo{ - Type: "jwt-hmac-secret", + Type: KTJwtHmacSecret, PrivateKey: sk, } @@ -63,7 +64,7 @@ func APISecret(keystore types.KeyStore, lr repo.LockedRepo) (*dtypes.APIAlg, err } // TODO: make this configurable - p := jwtPayload{ + p := JwtPayload{ Allow: apistruct.AllPermissions, }