From c5dc10ccaba573d75cbddf9704a8fe925cce8610 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Fri, 2 Jun 2023 10:18:18 +0200 Subject: [PATCH] cmd/litcli: add super macaroon helper commands In this commit, a `supermacrootkey` helper command is added which lets a user generate a random root key ID for a super macaroon along with an `issupermacaroon` command that allows a users to easily confirm if a macaroon is considered a super macaroon or not. Neither of these commands require a connection to LiTd. --- cmd/litcli/helpers.go | 125 ++++++++++++++++++++++++++++++++++++++++++ cmd/litcli/main.go | 1 + 2 files changed, 126 insertions(+) create mode 100644 cmd/litcli/helpers.go diff --git a/cmd/litcli/helpers.go b/cmd/litcli/helpers.go new file mode 100644 index 00000000..57924508 --- /dev/null +++ b/cmd/litcli/helpers.go @@ -0,0 +1,125 @@ +package main + +import ( + "bytes" + "crypto/rand" + "encoding/hex" + "encoding/json" + "os" + + "github.com/lightninglabs/lightning-terminal/session" + "github.com/urfave/cli" +) + +// helperCommands are commands that do not require a connection to LiTd to +// return a response. +var helperCommands = cli.Command{ + Name: "helper", + Usage: "helper commands", + Category: "Helper", + Subcommands: []cli.Command{ + generateSuperMacRootIDCmd, + isSuperMacaroonCmd, + }, +} + +// generateSuperMacRootIDCmd is a command that can be used to generate a root +// key ID for a super macaroon. A suffix may be specified. +var generateSuperMacRootIDCmd = cli.Command{ + Name: "supermacrootkey", + Usage: "Generate a valid super macaroon root key ID from scratch " + + "or from a given root key ID suffix", + Description: ` + This command can be used to generate a valid super macaroon root key ID + from scratch or from a given root key ID suffix. + `, + Action: superMacRootKey, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "root_key_suffix", + Usage: "A 4-byte suffix to use in the construction " + + "of the root key ID. If not provided, then a " + + "random one will be generated. This must be " + + "specified as a hex string using a maximum of " + + "8 characters.", + }, + }, +} + +// superMacRootKey generates a super macaroon root key ID. +func superMacRootKey(ctx *cli.Context) error { + var suffix [4]byte + + if ctx.IsSet("root_key_suffix") { + suffixBytes, err := hex.DecodeString( + ctx.String("root_key_suffix"), + ) + if err != nil { + return err + } + + copy(suffix[:], suffixBytes) + } else { + _, err := rand.Read(suffix[:]) + if err != nil { + return err + } + } + + id := session.NewSuperMacaroonRootKeyID(suffix) + + printJSON(struct { + RootKeyID uint64 `json:"root_key_id"` + }{ + RootKeyID: id, + }) + + return nil +} + +// isSuperMacaronoCmd is a command that a user can run in order to check if +// a macaroon is a super macaroon. +var isSuperMacaroonCmd = cli.Command{ + Name: "issupermacaroon", + Usage: "Prints 'true' if the given macaroon is a super macaroon", + Description: ` + This command can be used to verify if a macaroon is considered a + super macaroon. + `, + Action: isSuperMacaroon, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "mac", + Usage: "The hex-encoded macaroon", + Required: true, + }, + }, +} + +// isSuperMacaroon checks if the users given macaroon is considered a super +// macaroon. +func isSuperMacaroon(ctx *cli.Context) error { + isSuperMac := session.IsSuperMacaroon(ctx.String("mac")) + + printJSON(struct { + IsSuperMacaroon bool `json:"is_super_macaroon"` + }{ + IsSuperMacaroon: isSuperMac, + }) + + return nil +} + +// printJSON marshals the given interface as a json byte slice, formats it to +// use easy to read indentation and writes it as a string to standard out. +func printJSON(resp interface{}) { + b, err := json.Marshal(resp) + if err != nil { + fatal(err) + } + + var out bytes.Buffer + json.Indent(&out, b, "", "\t") + out.WriteString("\n") + out.WriteTo(os.Stdout) +} diff --git a/cmd/litcli/main.go b/cmd/litcli/main.go index 1bb59912..8c40775d 100644 --- a/cmd/litcli/main.go +++ b/cmd/litcli/main.go @@ -76,6 +76,7 @@ func main() { app.Commands = append(app.Commands, privacyMapCommands) app.Commands = append(app.Commands, autopilotCommands) app.Commands = append(app.Commands, litCommands...) + app.Commands = append(app.Commands, helperCommands) err := app.Run(os.Args) if err != nil {