lightning-terminal/cmd/litcli/sessions.go
ffranr a0e63124c0
multi: reformat long lines for readability
- Replace occurrences of `// nolint:lll` with `// nolint:ll` across
  files for consistency.
- Reformat multiline strings, comments, and function parameters to
  improve clarity and adhere to style guidelines.
- Add `// nolint:ll` comments where necessary to prevent linter
  warnings.
2025-12-09 16:12:03 +00:00

306 lines
7.7 KiB
Go

package main
import (
"encoding/hex"
"fmt"
"time"
"github.com/lightninglabs/lightning-terminal/litrpc"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/urfave/cli"
)
var (
// defaultSessionExpiry is the default time a session can be used for.
// The current value evaluates to 90 days.
defaultSessionExpiry = time.Hour * 24 * 90
labelFlag = cli.StringFlag{
Name: "label",
Usage: "The session label.",
Required: true,
}
expiryFlag = cli.Uint64Flag{
Name: "expiry",
Usage: "The number of seconds that the session should " +
"remain active.",
Value: uint64(defaultSessionExpiry.Seconds()),
}
mailboxServerAddrFlag = cli.StringFlag{
Name: "mailboxserveraddr",
Usage: "The host:port of the mailbox server to be used.",
Value: "mailbox.terminal.lightning.today:443",
}
devserver = cli.BoolFlag{
Name: "devserver",
Usage: "Set to true to skip verification of the " +
"server's tls cert.",
}
)
var sessionCommands = []cli.Command{
{
Name: "sessions",
ShortName: "s",
Usage: "Manage Lightning Node Connect sessions",
Category: "LNC",
Subcommands: []cli.Command{
addSessionCommand,
listSessionCommand,
revokeSessionCommand,
},
Description: "Manage Lightning Node Connect sessions.",
},
}
var addSessionCommand = cli.Command{
Name: "add",
ShortName: "a",
Usage: "Create a new Lightning Node Connect session.",
Description: "Add a new active session.",
Action: addSession,
Flags: []cli.Flag{
labelFlag,
expiryFlag,
mailboxServerAddrFlag,
devserver,
cli.StringFlag{
Name: "type",
Usage: "The session type to be created which will " +
"determine the permissions a user has when " +
"connecting with the session; options " +
"include readonly|admin|account|custom.",
Value: "readonly",
},
cli.StringSliceFlag{
Name: "uri",
Usage: "The URI that should be included in the " +
"macaroon of a custom session. Note that " +
"this flag will only be used if the 'type' " +
"flag is set to 'custom'. This flag can be " +
"specified multiple times if multiple URIs " +
"should be included. Note that a regex can " +
"also be specified which will then result in " +
"all URIs matching the regex to be included. " +
"For example, '/lnrpc\\..*' will result in " +
"all `lnrpc` permissions being included.",
},
cli.StringFlag{
Name: "account_id",
Usage: "The account id that should be used for " +
"the account session. Note that this flag " +
"will only be used if the 'type' flag is " +
"set to 'account'.",
},
},
}
func addSession(cli *cli.Context) error {
clientConn, cleanup, err := connectClient(cli, false)
if err != nil {
return err
}
defer cleanup()
client := litrpc.NewSessionsClient(clientConn)
sessTypeStr := cli.String("type")
sessType, err := parseSessionType(sessTypeStr)
if err != nil {
return err
}
var macPerms []*litrpc.MacaroonPermission
for _, uri := range cli.StringSlice("uri") {
macPerms = append(macPerms, &litrpc.MacaroonPermission{
Entity: macaroons.PermissionEntityCustomURI,
Action: uri,
})
}
sessionLength := time.Second * time.Duration(cli.Uint64("expiry"))
sessionExpiry := time.Now().Add(sessionLength).Unix()
ctx := getContext()
req := litrpc.AddSessionRequest{
Label: cli.String("label"),
SessionType: sessType,
ExpiryTimestampSeconds: uint64(sessionExpiry),
MailboxServerAddr: cli.String("mailboxserveraddr"),
DevServer: cli.Bool("devserver"),
MacaroonCustomPermissions: macPerms,
AccountId: cli.String("account_id"),
}
resp, err := client.AddSession(ctx, &req)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
func parseSessionType(sessionType string) (litrpc.SessionType, error) {
switch sessionType {
case "admin":
return litrpc.SessionType_TYPE_MACAROON_ADMIN, nil
case "readonly":
return litrpc.SessionType_TYPE_MACAROON_READONLY, nil
case "account":
return litrpc.SessionType_TYPE_MACAROON_ACCOUNT, nil
case "custom":
return litrpc.SessionType_TYPE_MACAROON_CUSTOM, nil
default:
return 0, fmt.Errorf("unsupported session type %s", sessionType)
}
}
var listSessionCommand = cli.Command{
Name: "list",
ShortName: "l",
Usage: "List Lightning Node Connect sessions.",
Description: "List sessions.",
Subcommands: []cli.Command{
listAllSessionsCommand,
listRevokedSessions,
listInUseSessions,
listExpiredSessions,
listCreatedSessions,
},
}
var listAllSessionsCommand = cli.Command{
Name: "all",
ShortName: "a",
Usage: "List all Lightning Node Connect sessions.",
Description: "List all sessions.\n",
Action: listSessions(sessionFilterAll),
}
var listRevokedSessions = cli.Command{
Name: "revoked",
ShortName: "r",
Usage: "List revoked Lightning Node Connect sessions.",
Description: "List revoked sessions.\n",
Action: listSessions(sessionFilterRevoked),
}
var listInUseSessions = cli.Command{
Name: "inuse",
ShortName: "u",
Usage: "List in-use Lightning Node Connect sessions.",
Description: "List in-use sessions.\n",
Action: listSessions(sessionFilterInUse),
}
var listExpiredSessions = cli.Command{
Name: "expired",
ShortName: "e",
Usage: "List expired Lightning Node Connect sessions.",
Description: "List expired sessions.\n",
Action: listSessions(sessionFilterExpired),
}
var listCreatedSessions = cli.Command{
Name: "created",
ShortName: "c",
Usage: "List created Lightning Node Connect sessions.",
Description: "List created sessions.\n",
Action: listSessions(sessionFilterCreated),
}
type sessionFilter uint32
const (
sessionFilterAll sessionFilter = iota
sessionFilterExpired
sessionFilterInUse
sessionFilterRevoked
sessionFilterCreated
)
var sessionStateMap = map[litrpc.SessionState]sessionFilter{
litrpc.SessionState_STATE_CREATED: sessionFilterCreated,
litrpc.SessionState_STATE_EXPIRED: sessionFilterExpired,
litrpc.SessionState_STATE_IN_USE: sessionFilterInUse,
litrpc.SessionState_STATE_REVOKED: sessionFilterRevoked,
}
func listSessions(filter sessionFilter) func(ctx *cli.Context) error {
return func(cli *cli.Context) error {
clientConn, cleanup, err := connectClient(cli, false)
if err != nil {
return err
}
defer cleanup()
client := litrpc.NewSessionsClient(clientConn)
ctx := getContext()
resp, err := client.ListSessions(
ctx, &litrpc.ListSessionsRequest{},
)
if err != nil {
return err
}
if filter == sessionFilterAll {
printRespJSON(resp)
return nil
}
var sessions []*litrpc.Session
for _, session := range resp.Sessions {
if sessionStateMap[session.SessionState] != filter {
continue
}
sessions = append(sessions, session)
}
printRespJSON(&litrpc.ListSessionsResponse{Sessions: sessions})
return nil
}
}
var revokeSessionCommand = cli.Command{
Name: "revoke",
ShortName: "r",
Usage: "Revoke a Lightning Node Connect session.",
Description: "Revoke an active session.",
Action: revokeSession,
Flags: []cli.Flag{
cli.StringFlag{
Name: "localpubkey",
Usage: "The local pubkey of the session to revoke.",
Required: true,
},
},
}
func revokeSession(cli *cli.Context) error {
clientConn, cleanup, err := connectClient(cli, false)
if err != nil {
return err
}
defer cleanup()
client := litrpc.NewSessionsClient(clientConn)
pubkey, err := hex.DecodeString(cli.String("localpubkey"))
if err != nil {
return err
}
ctx := getContext()
resp, err := client.RevokeSession(
ctx, &litrpc.RevokeSessionRequest{
LocalPublicKey: pubkey,
},
)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}