lncli: support list/delete on marcaroon IDs
This commit is contained in:
parent
c0e2513350
commit
c8a2916d91
@ -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
|
||||
|
44
rpcserver.go
44
rpcserver.go
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user