From f4e1f60e4d08cc4a91e0078fe2754826c6e6f73f Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Thu, 12 May 2022 13:12:09 +0200 Subject: [PATCH] cmd/lncli: extract macaroon caveat flags As a preparation for re-using the macaroon caveat/constraints CLI flags, we extract the parsing and adding of those constraints into its own function. --- cmd/lncli/cmd_macaroon.go | 206 ++++++++++++++++++++------------------ 1 file changed, 111 insertions(+), 95 deletions(-) diff --git a/cmd/lncli/cmd_macaroon.go b/cmd/lncli/cmd_macaroon.go index a9fa7aa83..75d93371b 100644 --- a/cmd/lncli/cmd_macaroon.go +++ b/cmd/lncli/cmd_macaroon.go @@ -19,12 +19,36 @@ import ( "gopkg.in/macaroon.v2" ) +var ( + macTimeoutFlag = cli.Uint64Flag{ + Name: "timeout", + Usage: "the number of seconds the macaroon will be " + + "valid before it times out", + } + macIPAddressFlag = cli.StringFlag{ + Name: "ip_address", + Usage: "the IP address the macaroon will be bound to", + } + macCustomCaveatNameFlag = cli.StringFlag{ + Name: "custom_caveat_name", + Usage: "the name of the custom caveat to add", + } + macCustomCaveatConditionFlag = cli.StringFlag{ + Name: "custom_caveat_condition", + Usage: "the condition of the custom caveat to add, can be " + + "empty if custom caveat doesn't need a value", + } +) + var bakeMacaroonCommand = cli.Command{ Name: "bakemacaroon", Category: "Macaroons", Usage: "Bakes a new macaroon with the provided list of permissions " + "and restrictions.", - ArgsUsage: "[--save_to=] [--timeout=] [--ip_address=] [--allow_external_permissions] permissions...", + ArgsUsage: "[--save_to=] [--timeout=] [--ip_address=] " + + "[--custom_caveat_name= [--custom_caveat_condition=]] " + + "[--root_key_id=] [--allow_external_permissions] " + + "permissions...", Description: ` Bake a new macaroon that grants the provided permissions and optionally adds restrictions (timeout, IP address) to it. @@ -57,32 +81,19 @@ var bakeMacaroonCommand = cli.Command{ Usage: "save the created macaroon to this file " + "using the default binary format", }, + macTimeoutFlag, + macIPAddressFlag, + macCustomCaveatNameFlag, + macCustomCaveatConditionFlag, cli.Uint64Flag{ - Name: "timeout", - Usage: "the number of seconds the macaroon will be " + - "valid before it times out", - }, - cli.StringFlag{ - Name: "ip_address", - Usage: "the IP address the macaroon will be bound to", - }, - cli.StringFlag{ - Name: "custom_caveat_name", - Usage: "the name of the custom caveat to add", - }, - cli.StringFlag{ - Name: "custom_caveat_condition", - Usage: "the condition of the custom caveat to add, " + - "can be empty if custom caveat doesn't need " + - "a value", - }, - cli.Uint64Flag{ - Name: "root_key_id", - Usage: "the numerical root key ID used to create the macaroon", + Name: "root_key_id", + Usage: "the numerical root key ID used to create the " + + "macaroon", }, cli.BoolFlag{ - Name: "allow_external_permissions", - Usage: "whether permissions lnd is not familiar with are allowed", + Name: "allow_external_permissions", + Usage: "whether permissions lnd is not familiar with " + + "are allowed", }, }, Action: actionDecorator(bakeMacaroon), @@ -101,10 +112,6 @@ func bakeMacaroon(ctx *cli.Context) error { var ( savePath string - timeout int64 - ipAddress net.IP - customCaveatName string - customCaveatCond string rootKeyID uint64 parsedPermissions []*lnrpc.MacaroonPermission err error @@ -114,47 +121,6 @@ func bakeMacaroon(ctx *cli.Context) error { savePath = lncfg.CleanAndExpandPath(ctx.String("save_to")) } - if ctx.IsSet("timeout") { - timeout = ctx.Int64("timeout") - if timeout <= 0 { - return fmt.Errorf("timeout must be greater than 0") - } - } - - if ctx.IsSet("ip_address") { - ipAddress = net.ParseIP(ctx.String("ip_address")) - if ipAddress == nil { - return fmt.Errorf("unable to parse ip_address: %s", - ctx.String("ip_address")) - } - } - - if ctx.IsSet("custom_caveat_name") { - customCaveatName = ctx.String("custom_caveat_name") - if containsWhiteSpace(customCaveatName) { - return fmt.Errorf("unexpected white space found in " + - "custom caveat name") - } - if customCaveatName == "" { - return fmt.Errorf("invalid custom caveat name") - } - } - - if ctx.IsSet("custom_caveat_condition") { - customCaveatCond = ctx.String("custom_caveat_condition") - if containsWhiteSpace(customCaveatCond) { - return fmt.Errorf("unexpected white space found in " + - "custom caveat condition") - } - if customCaveatCond == "" { - return fmt.Errorf("invalid custom caveat condition") - } - if customCaveatCond != "" && customCaveatName == "" { - return fmt.Errorf("cannot set custom caveat " + - "condition without custom caveat name") - } - } - if ctx.IsSet("root_key_id") { rootKeyID = ctx.Uint64("root_key_id") } @@ -213,32 +179,7 @@ func bakeMacaroon(ctx *cli.Context) error { // Now apply the desired constraints to the macaroon. This will always // create a new macaroon object, even if no constraints are added. - macConstraints := make([]macaroons.Constraint, 0) - if timeout > 0 { - macConstraints = append( - macConstraints, macaroons.TimeoutConstraint(timeout), - ) - } - if ipAddress != nil { - macConstraints = append( - macConstraints, - macaroons.IPLockConstraint(ipAddress.String()), - ) - } - - // The custom caveat condition is optional, it could just be a marker - // tag in the macaroon with just a name. The interceptor itself doesn't - // care about the value anyway. - if customCaveatName != "" { - macConstraints = append( - macConstraints, macaroons.CustomConstraint( - customCaveatName, customCaveatCond, - ), - ) - } - constrainedMac, err := macaroons.AddConstraints( - unmarshalMac, macConstraints..., - ) + constrainedMac, err := applyMacaroonConstraints(ctx, unmarshalMac) if err != nil { return err } @@ -470,6 +411,81 @@ func printMacaroon(ctx *cli.Context) error { return nil } +// applyMacaroonConstraints parses and applies all currently supported macaroon +// condition flags from the command line to the given macaroon and returns a new +// macaroon instance. +func applyMacaroonConstraints(ctx *cli.Context, + mac *macaroon.Macaroon) (*macaroon.Macaroon, error) { + + macConstraints := make([]macaroons.Constraint, 0) + + if ctx.IsSet(macTimeoutFlag.Name) { + timeout := ctx.Int64(macTimeoutFlag.Name) + if timeout <= 0 { + return nil, fmt.Errorf("timeout must be greater than 0") + } + macConstraints = append( + macConstraints, macaroons.TimeoutConstraint(timeout), + ) + } + + if ctx.IsSet(macIPAddressFlag.Name) { + ipAddress := net.ParseIP(ctx.String(macIPAddressFlag.Name)) + if ipAddress == nil { + return nil, fmt.Errorf("unable to parse ip_address: %s", + ctx.String("ip_address")) + } + + macConstraints = append( + macConstraints, + macaroons.IPLockConstraint(ipAddress.String()), + ) + } + + if ctx.IsSet(macCustomCaveatNameFlag.Name) { + customCaveatName := ctx.String(macCustomCaveatNameFlag.Name) + if containsWhiteSpace(customCaveatName) { + return nil, fmt.Errorf("unexpected white space found " + + "in custom caveat name") + } + if customCaveatName == "" { + return nil, fmt.Errorf("invalid custom caveat name") + } + + var customCaveatCond string + if ctx.IsSet(macCustomCaveatConditionFlag.Name) { + customCaveatCond = ctx.String( + macCustomCaveatConditionFlag.Name, + ) + if containsWhiteSpace(customCaveatCond) { + return nil, fmt.Errorf("unexpected white " + + "space found in custom caveat " + + "condition") + } + if customCaveatCond == "" { + return nil, fmt.Errorf("invalid custom " + + "caveat condition") + } + } + + // The custom caveat condition is optional, it could just be a + // marker tag in the macaroon with just a name. The interceptor + // itself doesn't care about the value anyway. + macConstraints = append( + macConstraints, macaroons.CustomConstraint( + customCaveatName, customCaveatCond, + ), + ) + } + + constrainedMac, err := macaroons.AddConstraints(mac, macConstraints...) + if err != nil { + return nil, fmt.Errorf("error adding constraints: %v", err) + } + + return constrainedMac, nil +} + // containsWhiteSpace returns true if the given string contains any character // that is considered to be a white space or non-printable character such as // space, tabulator, newline, carriage return and some more exotic ones.