mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
Merge pull request #1317 from Cyberguru1/custom-session-permissions
Some checks failed
CI / frontend tests on macOS-latest (push) Has been cancelled
CI / frontend tests on ubuntu-latest (push) Has been cancelled
CI / frontend tests on windows-latest (push) Has been cancelled
CI / backend build on macOS-latest (push) Has been cancelled
CI / backend build on ubuntu-latest (push) Has been cancelled
CI / backend build on windows-latest (push) Has been cancelled
CI / cross compilation (push) Has been cancelled
CI / cross compilation-1 (push) Has been cancelled
CI / cross compilation-2 (push) Has been cancelled
CI / RPC proto compilation check (push) Has been cancelled
CI / check commits (push) Has been cancelled
CI / Sqlc check (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / run unit tests (push) Has been cancelled
CI / run unit tests-1 (push) Has been cancelled
CI / run unit tests-2 (push) Has been cancelled
CI / run unit tests-3 (push) Has been cancelled
CI / build itest binaries (push) Has been cancelled
CI / check release notes updated (push) Has been cancelled
CI / integration test (push) Has been cancelled
CI / integration test-1 (push) Has been cancelled
CI / integration test-2 (push) Has been cancelled
Some checks failed
CI / frontend tests on macOS-latest (push) Has been cancelled
CI / frontend tests on ubuntu-latest (push) Has been cancelled
CI / frontend tests on windows-latest (push) Has been cancelled
CI / backend build on macOS-latest (push) Has been cancelled
CI / backend build on ubuntu-latest (push) Has been cancelled
CI / backend build on windows-latest (push) Has been cancelled
CI / cross compilation (push) Has been cancelled
CI / cross compilation-1 (push) Has been cancelled
CI / cross compilation-2 (push) Has been cancelled
CI / RPC proto compilation check (push) Has been cancelled
CI / check commits (push) Has been cancelled
CI / Sqlc check (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / run unit tests (push) Has been cancelled
CI / run unit tests-1 (push) Has been cancelled
CI / run unit tests-2 (push) Has been cancelled
CI / run unit tests-3 (push) Has been cancelled
CI / build itest binaries (push) Has been cancelled
CI / check release notes updated (push) Has been cancelled
CI / integration test (push) Has been cancelled
CI / integration test-1 (push) Has been cancelled
CI / integration test-2 (push) Has been cancelled
sessions: support entity:action format for custom sessions
This commit is contained in:
commit
916ca71d70
5 changed files with 346 additions and 6 deletions
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/litrpc"
|
||||
|
|
@ -85,6 +86,20 @@ var addSessionCommand = cli.Command{
|
|||
"For example, '/lnrpc\\..*' will result in " +
|
||||
"all `lnrpc` permissions being included.",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
Name: "permission",
|
||||
Usage: "A permission that should be included in the " +
|
||||
"macaroon of a custom session, in the " +
|
||||
"format entity:action (e.g. info:read), " +
|
||||
"similar to lncli bakemacaroon. " +
|
||||
"Note that this flag will only be used if " +
|
||||
"the 'type' flag is set to 'custom'. " +
|
||||
"This flag can be specified multiple times, " +
|
||||
"comma-separated, or mixed (e.g., " +
|
||||
"'info:read,onchain:write' or " +
|
||||
"--permission info:read --permission " +
|
||||
"onchain:write).",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "account_id",
|
||||
Usage: "The account id that should be used for " +
|
||||
|
|
@ -109,12 +124,12 @@ func addSession(cli *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var macPerms []*litrpc.MacaroonPermission
|
||||
for _, uri := range cli.StringSlice("uri") {
|
||||
macPerms = append(macPerms, &litrpc.MacaroonPermission{
|
||||
Entity: macaroons.PermissionEntityCustomURI,
|
||||
Action: uri,
|
||||
})
|
||||
macPerms, err := parseCustomPermissions(
|
||||
cli.StringSlice("uri"),
|
||||
cli.StringSlice("permission"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sessionLength := time.Second * time.Duration(cli.Uint64("expiry"))
|
||||
|
|
@ -304,3 +319,51 @@ func revokeSession(cli *cli.Context) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseCustomPermissions(uris, permissions []string) (
|
||||
[]*litrpc.MacaroonPermission, error) {
|
||||
|
||||
var macPerms []*litrpc.MacaroonPermission
|
||||
|
||||
for _, uri := range uris {
|
||||
macPerms = append(macPerms, &litrpc.MacaroonPermission{
|
||||
Entity: macaroons.PermissionEntityCustomURI,
|
||||
Action: uri,
|
||||
})
|
||||
}
|
||||
|
||||
for _, perm := range permissions {
|
||||
parts := strings.Split(perm, ",")
|
||||
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
|
||||
if part == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
subParts := strings.Split(part, ":")
|
||||
if len(subParts) != 2 {
|
||||
return nil, fmt.Errorf("invalid permission "+
|
||||
"format '%s', must be entity:action",
|
||||
part)
|
||||
}
|
||||
|
||||
entity := strings.TrimSpace(subParts[0])
|
||||
action := strings.TrimSpace(subParts[1])
|
||||
|
||||
if entity == "" || action == "" {
|
||||
return nil, fmt.Errorf("invalid permission "+
|
||||
"format '%s', entity and action "+
|
||||
"must not be empty", part)
|
||||
}
|
||||
|
||||
macPerms = append(macPerms, &litrpc.MacaroonPermission{
|
||||
Entity: entity,
|
||||
Action: action,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return macPerms, nil
|
||||
}
|
||||
|
|
|
|||
173
cmd/litcli/sessions_test.go
Normal file
173
cmd/litcli/sessions_test.go
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/lightninglabs/lightning-terminal/litrpc"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// TestParseCustomPermissions tests that custom permissions (URIs and
|
||||
// entity:action pairs) are parsed and validated correctly.
|
||||
func TestParseCustomPermissions(t *testing.T) {
|
||||
customURI := macaroons.PermissionEntityCustomURI
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
uris []string
|
||||
permissions []string
|
||||
expected []*litrpc.MacaroonPermission
|
||||
expectErr bool
|
||||
errContains string
|
||||
}{
|
||||
{
|
||||
name: "valid URIs only",
|
||||
uris: []string{
|
||||
"/lnrpc.Lightning/GetInfo",
|
||||
"/lnrpc.Lightning/UpdateChannelPolicy",
|
||||
},
|
||||
permissions: nil,
|
||||
expected: []*litrpc.MacaroonPermission{
|
||||
{
|
||||
Entity: customURI,
|
||||
Action: "/lnrpc.Lightning/GetInfo",
|
||||
},
|
||||
{
|
||||
Entity: customURI,
|
||||
Action: "/lnrpc.Lightning/" +
|
||||
"UpdateChannelPolicy",
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid permissions only - repeated flags",
|
||||
uris: nil,
|
||||
permissions: []string{
|
||||
"info:read",
|
||||
"offchain:write",
|
||||
},
|
||||
expected: []*litrpc.MacaroonPermission{
|
||||
{
|
||||
Entity: "info",
|
||||
Action: "read",
|
||||
},
|
||||
{
|
||||
Entity: "offchain",
|
||||
Action: "write",
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid permissions only - comma separated",
|
||||
uris: nil,
|
||||
permissions: []string{
|
||||
"info:read,offchain:write",
|
||||
},
|
||||
expected: []*litrpc.MacaroonPermission{
|
||||
{
|
||||
Entity: "info",
|
||||
Action: "read",
|
||||
},
|
||||
{
|
||||
Entity: "offchain",
|
||||
Action: "write",
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid permissions only - mixed with whitespace",
|
||||
uris: nil,
|
||||
permissions: []string{
|
||||
" info:read , offchain:write ",
|
||||
},
|
||||
expected: []*litrpc.MacaroonPermission{
|
||||
{
|
||||
Entity: "info",
|
||||
Action: "read",
|
||||
},
|
||||
{
|
||||
Entity: "offchain",
|
||||
Action: "write",
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "combination of URIs and permissions",
|
||||
uris: []string{
|
||||
"/lnrpc.Lightning/GetInfo",
|
||||
},
|
||||
permissions: []string{
|
||||
"info:read,offchain:write",
|
||||
"onchain:read",
|
||||
},
|
||||
expected: []*litrpc.MacaroonPermission{
|
||||
{
|
||||
Entity: customURI,
|
||||
Action: "/lnrpc.Lightning/GetInfo",
|
||||
},
|
||||
{
|
||||
Entity: "info",
|
||||
Action: "read",
|
||||
},
|
||||
{
|
||||
Entity: "offchain",
|
||||
Action: "write",
|
||||
},
|
||||
{
|
||||
Entity: "onchain",
|
||||
Action: "read",
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid perm - missing colon",
|
||||
uris: nil,
|
||||
permissions: []string{"inforead"},
|
||||
expectErr: true,
|
||||
errContains: "must be entity:action",
|
||||
},
|
||||
{
|
||||
name: "invalid perm - multiple colons",
|
||||
uris: nil,
|
||||
permissions: []string{"info:read:extra"},
|
||||
expectErr: true,
|
||||
errContains: "must be entity:action",
|
||||
},
|
||||
{
|
||||
name: "invalid perm - empty entity",
|
||||
uris: nil,
|
||||
permissions: []string{":read"},
|
||||
expectErr: true,
|
||||
errContains: "entity and action must not be empty",
|
||||
},
|
||||
{
|
||||
name: "invalid perm - empty action",
|
||||
uris: nil,
|
||||
permissions: []string{"info:"},
|
||||
expectErr: true,
|
||||
errContains: "entity and action must not be empty",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
actual, err := parseCustomPermissions(
|
||||
tt.uris, tt.permissions,
|
||||
)
|
||||
if tt.expectErr {
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), tt.errContains)
|
||||
require.Nil(t, actual)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expected, actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -85,6 +85,12 @@
|
|||
`litcli accounts update debit` and `litcli accounts update credit` commands
|
||||
to modify an account's balance.
|
||||
|
||||
* [Add custom permissions support to sessions](https://github.com/lightninglabs/lightning-terminal/pull/1317):
|
||||
Added the `--permission` flag to `litcli sessions add` to allow specifying
|
||||
custom `entity:action` permissions (e.g. `info:read`), similar to
|
||||
`lncli bakemacaroon`, for sessions of type `custom`. Supports repeated flags,
|
||||
comma-separated lists, and mixed input.
|
||||
|
||||
### Technical and Architectural Updates
|
||||
|
||||
## RPC Updates
|
||||
|
|
|
|||
|
|
@ -692,6 +692,55 @@ func integratedTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
|
|||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("lnc auth custom entity action perms", func(tt *testing.T) {
|
||||
cfg := net.Alice.Cfg
|
||||
|
||||
ctx := context.Background()
|
||||
ctxt, cancel := context.WithTimeout(ctx, defaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
customPerms := []*litrpc.MacaroonPermission{
|
||||
{
|
||||
Entity: "info",
|
||||
Action: "read",
|
||||
},
|
||||
}
|
||||
|
||||
rawLNCConn := setUpLNCConn(
|
||||
ctxt, t, cfg.LitAddr(), cfg.LitTLSCertPath,
|
||||
cfg.LitMacPath,
|
||||
litrpc.SessionType_TYPE_MACAROON_CUSTOM,
|
||||
customPerms,
|
||||
)
|
||||
defer rawLNCConn.Close()
|
||||
|
||||
for _, endpoint := range endpoints {
|
||||
endpoint := endpoint
|
||||
endpointDisabled := subServersDisabled &&
|
||||
endpoint.canDisable
|
||||
|
||||
expectedErr := "permission denied"
|
||||
if endpoint.noAuth {
|
||||
expectedErr = "unknown service"
|
||||
}
|
||||
|
||||
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
|
||||
// Only lnrpc (GetInfo) is allowed, as we
|
||||
// only granted the "info:read" permission.
|
||||
allowed := endpoint.name == "lnrpc"
|
||||
|
||||
runLNCAuthTest(
|
||||
ttt, rawLNCConn, endpoint.requestFn,
|
||||
endpoint.successPattern,
|
||||
allowed, expectedErr,
|
||||
endpointDisabled,
|
||||
endpoint.disabledPattern,
|
||||
endpoint.noAuth,
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func uiPasswordAuthCheck(t *testing.T, cfg *LitNodeConfig, subServersDisabled,
|
||||
|
|
|
|||
|
|
@ -259,6 +259,55 @@ func remoteTestSuite(ctx context.Context, net *NetworkHarness, t *testing.T,
|
|||
}
|
||||
})
|
||||
|
||||
t.Run("lnc auth custom entity action perms", func(tt *testing.T) {
|
||||
cfg := net.Bob.Cfg
|
||||
|
||||
ctx := context.Background()
|
||||
ctxt, cancel := context.WithTimeout(ctx, defaultTimeout)
|
||||
defer cancel()
|
||||
|
||||
customPerms := []*litrpc.MacaroonPermission{
|
||||
{
|
||||
Entity: "info",
|
||||
Action: "read",
|
||||
},
|
||||
}
|
||||
|
||||
rawLNCConn := setUpLNCConn(
|
||||
ctxt, tt, cfg.LitAddr(), cfg.LitTLSCertPath,
|
||||
cfg.LitMacPath,
|
||||
litrpc.SessionType_TYPE_MACAROON_CUSTOM,
|
||||
customPerms,
|
||||
)
|
||||
defer rawLNCConn.Close()
|
||||
|
||||
for _, endpoint := range endpoints {
|
||||
endpoint := endpoint
|
||||
endpointDisabled := subServersDisabled &&
|
||||
endpoint.canDisable
|
||||
|
||||
expectedErr := "permission denied"
|
||||
if endpoint.noAuth {
|
||||
expectedErr = "unknown service"
|
||||
}
|
||||
|
||||
tt.Run(endpoint.name+" lit port", func(ttt *testing.T) {
|
||||
// Only lnrpc (GetInfo) is allowed, as we
|
||||
// only granted the "info:read" permission.
|
||||
allowed := endpoint.name == "lnrpc"
|
||||
|
||||
runLNCAuthTest(
|
||||
ttt, rawLNCConn, endpoint.requestFn,
|
||||
endpoint.successPattern,
|
||||
allowed, expectedErr,
|
||||
endpointDisabled,
|
||||
endpoint.disabledPattern,
|
||||
endpoint.noAuth,
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("gRPC super macaroon account system test", func(tt *testing.T) {
|
||||
cfg := net.Bob.Cfg
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue