lncli: support list/delete on marcaroon IDs

This commit is contained in:
yyforyongyu 2020-07-24 00:37:13 +08:00
parent c0e2513350
commit c8a2916d91
No known key found for this signature in database
GPG Key ID: 9BCD95C4FF296868
6 changed files with 123 additions and 23 deletions

@ -1,11 +1,13 @@
package main
import (
"bytes"
"context"
"encoding/hex"
"fmt"
"io/ioutil"
"net"
"strconv"
"strings"
"github.com/lightningnetwork/lnd/lnrpc"
@ -18,7 +20,7 @@ var bakeMacaroonCommand = cli.Command{
Name: "bakemacaroon",
Category: "Macaroons",
Usage: "Bakes a new macaroon with the provided list of permissions " +
"and restrictions",
"and restrictions.",
ArgsUsage: "[--save_to=] [--timeout=] [--ip_address=] permissions...",
Description: `
Bake a new macaroon that grants the provided permissions and
@ -48,6 +50,10 @@ var bakeMacaroonCommand = cli.Command{
Name: "ip_address",
Usage: "the IP address the macaroon will be bound to",
},
cli.Uint64Flag{
Name: "root_key_id",
Usage: "the numerical root key ID used to create the macaroon",
},
},
Action: actionDecorator(bakeMacaroon),
}
@ -66,6 +72,7 @@ func bakeMacaroon(ctx *cli.Context) error {
savePath string
timeout int64
ipAddress net.IP
rootKeyID uint64
parsedPermissions []*lnrpc.MacaroonPermission
err error
)
@ -89,6 +96,10 @@ func bakeMacaroon(ctx *cli.Context) error {
}
}
if ctx.IsSet("root_key_id") {
rootKeyID = ctx.Uint64("root_key_id")
}
// A command line argument can't be an empty string. So we'll check each
// entry if it's a valid entity:action tuple. The content itself is
// validated server side. We just make sure we can parse it correctly.
@ -122,6 +133,7 @@ func bakeMacaroon(ctx *cli.Context) error {
// RPC call.
req := &lnrpc.BakeMacaroonRequest{
Permissions: parsedPermissions,
RootKeyId: rootKeyID,
}
resp, err := client.BakeMacaroon(context.Background(), req)
if err != nil {
@ -180,3 +192,80 @@ func bakeMacaroon(ctx *cli.Context) error {
return nil
}
var listMacaroonIDsCommand = cli.Command{
Name: "listmacaroonids",
Category: "Macaroons",
Usage: "List all macaroons root key IDs in use.",
Action: actionDecorator(listMacaroonIDs),
}
func listMacaroonIDs(ctx *cli.Context) error {
client, cleanUp := getClient(ctx)
defer cleanUp()
req := &lnrpc.ListMacaroonIDsRequest{}
resp, err := client.ListMacaroonIDs(context.Background(), req)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
var deleteMacaroonIDCommand = cli.Command{
Name: "deletemacaroonid",
Category: "Macaroons",
Usage: "Delete a specific macaroon ID.",
ArgsUsage: "root_key_id",
Description: `
Remove a macaroon ID using the specified root key ID. For example:
lncli deletemacaroonid 1
WARNING
When the ID is deleted, all macaroons created from that root key will
be invalidated.
Note that the default root key ID 0 cannot be deleted.
`,
Action: actionDecorator(deleteMacaroonID),
}
func deleteMacaroonID(ctx *cli.Context) error {
client, cleanUp := getClient(ctx)
defer cleanUp()
// Validate args length. Only one argument is allowed.
if ctx.NArg() != 1 {
return cli.ShowCommandHelp(ctx, "deletemacaroonid")
}
rootKeyIDString := ctx.Args().First()
// Convert string into uint64.
rootKeyID, err := strconv.ParseUint(rootKeyIDString, 10, 64)
if err != nil {
return fmt.Errorf("root key ID must be a positive integer")
}
// Check that the value is not equal to DefaultRootKeyID. Note that the
// server also validates the root key ID when removing it. However, we check
// it here too so that we can give users a nice warning.
if bytes.Equal([]byte(rootKeyIDString), macaroons.DefaultRootKeyID) {
return fmt.Errorf("deleting the default root key ID 0 is not allowed")
}
// Make the actual RPC call.
req := &lnrpc.DeleteMacaroonIDRequest{
RootKeyId: rootKeyID,
}
resp, err := client.DeleteMacaroonID(context.Background(), req)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}

@ -301,6 +301,8 @@ func main() {
verifyChanBackupCommand,
restoreChanBackupCommand,
bakeMacaroonCommand,
listMacaroonIDsCommand,
deleteMacaroonIDCommand,
trackPaymentCommand,
versionCommand,
}

@ -101,7 +101,8 @@ func New(cfg *Config) (*Server, lnrpc.MacaroonPerms, error) {
// yet, exist, so we need to create it with the help of the
// main macaroon service.
invoicesMac, err := cfg.MacService.NewMacaroon(
context.Background(), macaroons.DefaultRootKeyID, macaroonOps...,
context.Background(), macaroons.DefaultRootKeyID,
macaroonOps...,
)
if err != nil {
return nil, nil, err

@ -166,7 +166,8 @@ func New(cfg *Config) (*Server, lnrpc.MacaroonPerms, error) {
// exist, so we need to create it with the help of the main
// macaroon service.
routerMac, err := cfg.MacService.NewMacaroon(
context.Background(), macaroons.DefaultRootKeyID, macaroonOps...,
context.Background(), macaroons.DefaultRootKeyID,
macaroonOps...,
)
if err != nil {
return nil, nil, err

@ -113,7 +113,8 @@ func New(cfg *Config) (*Server, lnrpc.MacaroonPerms, error) {
// exist, so we need to create it with the help of the main
// macaroon service.
signerMac, err := cfg.MacService.NewMacaroon(
context.Background(), macaroons.DefaultRootKeyID, macaroonOps...,
context.Background(), macaroons.DefaultRootKeyID,
macaroonOps...,
)
if err != nil {
return nil, nil, err

@ -194,6 +194,12 @@ var (
"onchain", "offchain", "address", "message",
"peers", "info", "invoices", "signer", "macaroon",
}
// If the --no-macaroons flag is used to start lnd, the macaroon service
// is not initialized. errMacaroonDisabled is then returned when
// macaroon related services are used.
errMacaroonDisabled = fmt.Errorf("macaroon authentication disabled, " +
"remove --no-macaroons flag to enable")
)
// stringInSlice returns true if a string is contained in the given slice.
@ -6383,8 +6389,7 @@ func (r *rpcServer) BakeMacaroon(ctx context.Context,
// If the --no-macaroons flag is used to start lnd, the macaroon service
// is not initialized. Therefore we can't bake new macaroons.
if r.macService == nil {
return nil, fmt.Errorf("macaroon authentication disabled, " +
"remove --no-macaroons flag to enable")
return nil, errMacaroonDisabled
}
helpMsg := fmt.Sprintf("supported actions are %v, supported entities "+
@ -6416,10 +6421,11 @@ func (r *rpcServer) BakeMacaroon(ctx context.Context,
}
}
// Convert root key id from uint64 to bytes. Because the DefaultRootKeyID is
// a digit 0 expressed in a byte slice of a string "0", we will keep the IDs
// in the same format - all must be numeric, and must be a byte slice of
// string value of the digit, e.g., uint64(123) to string(123).
// Convert root key id from uint64 to bytes. Because the
// DefaultRootKeyID is a digit 0 expressed in a byte slice of a string
// "0", we will keep the IDs in the same format - all must be numeric,
// and must be a byte slice of string value of the digit, e.g.,
// uint64(123) to string(123).
rootKeyID := []byte(strconv.FormatUint(req.RootKeyId, 10))
// Bake new macaroon with the given permissions and send it binary
@ -6442,15 +6448,15 @@ func (r *rpcServer) BakeMacaroon(ctx context.Context,
// ListMacaroonIDs returns a list of macaroon root key IDs in use.
func (r *rpcServer) ListMacaroonIDs(ctx context.Context,
req *lnrpc.ListMacaroonIDsRequest) (*lnrpc.ListMacaroonIDsResponse, error) {
req *lnrpc.ListMacaroonIDsRequest) (
*lnrpc.ListMacaroonIDsResponse, error) {
rpcsLog.Debugf("[listmacaroonids]")
// If the --no-macaroons flag is used to start lnd, the macaroon service
// is not initialized. Therefore we can't show any IDs.
if r.macService == nil {
return nil, fmt.Errorf("macaroon authentication disabled, " +
"remove --no-macaroons flag to enable")
return nil, errMacaroonDisabled
}
rootKeyIDByteSlice, err := r.macService.ListMacaroonIDs(ctx)
@ -6474,21 +6480,21 @@ func (r *rpcServer) ListMacaroonIDs(ctx context.Context,
// DeleteMacaroonID removes a specific macaroon ID.
func (r *rpcServer) DeleteMacaroonID(ctx context.Context,
req *lnrpc.DeleteMacaroonIDRequest) (*lnrpc.DeleteMacaroonIDResponse, error) {
req *lnrpc.DeleteMacaroonIDRequest) (
*lnrpc.DeleteMacaroonIDResponse, error) {
rpcsLog.Debugf("[deletemacaroonid]")
// If the --no-macaroons flag is used to start lnd, the macaroon service
// is not initialized. Therefore we can't show any IDs.
// is not initialized. Therefore we can't delete any IDs.
if r.macService == nil {
return nil, fmt.Errorf("macaroon authentication disabled, " +
"remove --no-macaroons flag to enable")
return nil, errMacaroonDisabled
}
// Convert root key id from uint64 to bytes. Because the DefaultRootKeyID is
// a digit 0 expressed in a byte slice of a string "0", we will keep the IDs
// in the same format - all must be digit, and must be a byte slice of
// string value of the digit.
// Convert root key id from uint64 to bytes. Because the
// DefaultRootKeyID is a digit 0 expressed in a byte slice of a string
// "0", we will keep the IDs in the same format - all must be digit, and
// must be a byte slice of string value of the digit.
rootKeyID := []byte(strconv.FormatUint(req.RootKeyId, 10))
deletedIDBytes, err := r.macService.DeleteMacaroonID(ctx, rootKeyID)
if err != nil {
@ -6496,8 +6502,8 @@ func (r *rpcServer) DeleteMacaroonID(ctx context.Context,
}
return &lnrpc.DeleteMacaroonIDResponse{
// If the root key ID doesn't exist, it won't be deleted. We will return
// a response with deleted = false, otherwise true.
// If the root key ID doesn't exist, it won't be deleted. We
// will return a response with deleted = false, otherwise true.
Deleted: deletedIDBytes != nil,
}, nil
}