lncli: add custom caveats to bakemacaroon

With the new condition and checker in place, we can give the end user
the ability to add such a custom caveat to a baked macaroon.
There won't be an RPC counterpart for this operation since all first party
caveats currently are only added on the client side.
This commit is contained in:
Oliver Gugger committed 2021-09-20 13:05:47 +02:00
1 parent 045765111a
commit 7b822f41df
1 file changed
+57
+57
View File
@@ -8,6 +8,7 @@ import (
"net" "net"
"strconv" "strconv"
"strings" "strings"
"unicode"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/lightningnetwork/lnd/lncfg" "github.com/lightningnetwork/lnd/lncfg"
@@ -65,6 +66,16 @@ var bakeMacaroonCommand = cli.Command{
Name: "ip_address", Name: "ip_address",
Usage: "the IP address the macaroon will be bound to", 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{ cli.Uint64Flag{
Name: "root_key_id", Name: "root_key_id",
Usage: "the numerical root key ID used to create the macaroon", Usage: "the numerical root key ID used to create the macaroon",
@@ -92,6 +103,8 @@ func bakeMacaroon(ctx *cli.Context) error {
savePath string savePath string
timeout int64 timeout int64
ipAddress net.IP ipAddress net.IP
customCaveatName string
customCaveatCond string
rootKeyID uint64 rootKeyID uint64
parsedPermissions []*lnrpc.MacaroonPermission parsedPermissions []*lnrpc.MacaroonPermission
err error err error
@@ -116,6 +129,32 @@ func bakeMacaroon(ctx *cli.Context) error {
} }
} }
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") { if ctx.IsSet("root_key_id") {
rootKeyID = ctx.Uint64("root_key_id") rootKeyID = ctx.Uint64("root_key_id")
} }
@@ -186,6 +225,17 @@ func bakeMacaroon(ctx *cli.Context) error {
macaroons.IPLockConstraint(ipAddress.String()), 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( constrainedMac, err := macaroons.AddConstraints(
unmarshalMac, macConstraints..., unmarshalMac, macConstraints...,
) )
@@ -419,3 +469,10 @@ func printMacaroon(ctx *cli.Context) error {
return nil return 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.
func containsWhiteSpace(str string) bool {
return strings.IndexFunc(str, unicode.IsSpace) >= 0
}