diff --git a/cmd/neofs-cli/modules/util.go b/cmd/neofs-cli/modules/util.go new file mode 100644 index 00000000..5a646267 --- /dev/null +++ b/cmd/neofs-cli/modules/util.go @@ -0,0 +1,122 @@ +package cmd + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + + "github.com/nspcc-dev/neofs-api-go/pkg" + "github.com/nspcc-dev/neofs-api-go/pkg/token" + v2ACL "github.com/nspcc-dev/neofs-api-go/v2/acl" + "github.com/spf13/cobra" +) + +var ( + utilCmd = &cobra.Command{ + Use: "util", + Short: "Utility operations", + } + + signCmd = &cobra.Command{ + Use: "sign", + Short: "sign NeoFS structure", + } + + signBearerCmd = &cobra.Command{ + Use: "bearer-token", + Short: "sign bearer token to use it in requests", + RunE: signBearerToken, + } +) + +func init() { + rootCmd.AddCommand(utilCmd) + + utilCmd.AddCommand(signCmd) + + signCmd.AddCommand(signBearerCmd) + signBearerCmd.Flags().String("from", "", "File with JSON or binary encoded bearer token to sign") + _ = signBearerCmd.MarkFlagFilename("from") + _ = signBearerCmd.MarkFlagRequired("from") + signBearerCmd.Flags().String("to", "", "File to dump signed bearer token") + signBearerCmd.Flags().Bool("json", false, "Dump bearer token in JSON encoding") +} + +func signBearerToken(cmd *cobra.Command, _ []string) error { + btok, err := getBearerToken(cmd, "from") + if err != nil { + return err + } + + key, err := getKey() + if err != nil { + return err + } + + err = completeBearerToken(btok) + if err != nil { + return err + } + + err = btok.SignToken(key) + if err != nil { + return err + } + + to := cmd.Flag("to").Value.String() + jsonFlag, _ := cmd.Flags().GetBool("json") + + var data []byte + if jsonFlag || len(to) == 0 { + data = v2ACL.BearerTokenToJSON(btok.ToV2()) + if len(data) == 0 { + return errors.New("can't JSON encode bearer token") + } + } else { + data, err = btok.ToV2().StableMarshal(nil) + if err != nil { + return errors.New("can't binary encode bearer token") + } + } + + if len(to) == 0 { + prettyPrintJSON(cmd, data) + + return nil + } + + err = ioutil.WriteFile(to, data, 0644) + if err != nil { + return fmt.Errorf("can't write signed bearer token to file: %w", err) + } + + cmd.Printf("signed bearer token was successfully dumped to %s\n", to) + + return nil +} + +func completeBearerToken(btok *token.BearerToken) error { + if v2 := btok.ToV2(); v2 != nil { + // set eACL table version, because it usually omitted + table := v2.GetBody().GetEACL() + table.SetVersion(pkg.SDKVersion().ToV2()) + + // back to SDK token + btok = token.NewBearerTokenFromV2(v2) + } else { + return errors.New("unsupported bearer token version") + } + + return nil +} + +func prettyPrintJSON(cmd *cobra.Command, data []byte) { + buf := new(bytes.Buffer) + if err := json.Indent(buf, data, "", " "); err != nil { + printVerbose("Can't pretty print json: %w", err) + } + + cmd.Println(buf) +}