lightning-terminal/macaroons/super_mac_test.go
cyberguru1 3975e83006
macaroons: add super macaroon helpers
Introduce helper functions in the macaroons package to manage super
macaroon files and permissions. Add SuperMacaroonExists,
MacaroonMatchesPermissions, and BakeAndWriteSuperMacaroon.
2026-07-27 06:08:48 -05:00

167 lines
4.8 KiB
Go

package macaroons
import (
"encoding/hex"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"gopkg.in/macaroon-bakery.v2/bakery"
)
var (
// testMacHex is a read-only supermacaroon.
testMacHex = "0201036c6e6402f802030a1011540404373b4d0b3682b15ea7af60c" +
"c121431383434313932313339323432393138343738341a0f0a076163636" +
"f756e741204726561641a0f0a0761756374696f6e1204726561641a0d0a0" +
"561756469741204726561641a0c0a04617574681204726561641a0c0a046" +
"96e666f1204726561641a100a08696e7369676874731204726561641a100" +
"a08696e766f696365731204726561641a0f0a046c6f6f701202696e12036" +
"f75741a100a086d616361726f6f6e1204726561641a0f0a076d657373616" +
"7651204726561641a100a086f6666636861696e1204726561641a0f0a076" +
"f6e636861696e1204726561641a0d0a056f726465721204726561641a0d0" +
"a0570656572731204726561641a0d0a0572617465731204726561641a160" +
"a0e7265636f6d6d656e646174696f6e1204726561641a0e0a067265706f7" +
"2741204726561641a130a0b73756767657374696f6e731204726561641a0" +
"c0a04737761701204726561641a0d0a057465726d7312047265616400000" +
"6202362c91888e95dfbbf1eb995bd0fef2b549e2de7f4e9fa11aff445273" +
"60a6caf"
)
// TestSuperMacaroonRootKeyID tests that adding the super macaroon prefix to
// a root key ID results in a valid super macaroon root key ID.
func TestSuperMacaroonRootKeyID(t *testing.T) {
t.Parallel()
someBytes := [4]byte{02, 03, 44, 88}
rootKeyID := NewSuperMacaroonRootKeyID(someBytes)
require.True(t, isSuperMacaroonRootKeyID(rootKeyID))
require.False(t, isSuperMacaroonRootKeyID(123))
}
// TestIsSuperMacaroon tests that we can correctly identify an example super
// macaroon.
func TestIsSuperMacaroon(t *testing.T) {
t.Parallel()
require.True(t, IsSuperMacaroon(testMacHex))
}
// TestSuperMacaroonHelpers tests that SuperMacaroonExists and
// MacaroonMatchesPermissions behave correctly.
func TestSuperMacaroonHelpers(t *testing.T) {
t.Parallel()
tempDir := t.TempDir()
path := filepath.Join(tempDir, "test.macaroon")
// Verify that it doesn't exist yet.
require.False(t, SuperMacaroonExists(path))
// Write the test macaroon.
macBytes, err := hex.DecodeString(testMacHex)
require.NoError(t, err)
err = os.WriteFile(path, macBytes, 0600)
require.NoError(t, err)
// Now it should exist.
require.True(t, SuperMacaroonExists(path))
// The macaroon matches this expected list of permissions.
expectedPerms := []bakery.Op{
{Entity: "account", Action: "read"},
{Entity: "auction", Action: "read"},
{Entity: "audit", Action: "read"},
{Entity: "auth", Action: "read"},
{Entity: "info", Action: "read"},
{Entity: "insights", Action: "read"},
{Entity: "invoices", Action: "read"},
{Entity: "loop", Action: "in"},
{Entity: "loop", Action: "out"},
{Entity: "macaroon", Action: "read"},
{Entity: "message", Action: "read"},
{Entity: "offchain", Action: "read"},
{Entity: "onchain", Action: "read"},
{Entity: "order", Action: "read"},
{Entity: "peers", Action: "read"},
{Entity: "rates", Action: "read"},
{Entity: "recommendation", Action: "read"},
{Entity: "report", Action: "read"},
{Entity: "suggestions", Action: "read"},
{Entity: "swap", Action: "read"},
{Entity: "terms", Action: "read"},
}
matches, err := MacaroonMatchesPermissions(path, expectedPerms)
require.NoError(t, err)
require.True(t, matches)
// A subset of permissions should NOT match exactly.
matches, err = MacaroonMatchesPermissions(path, expectedPerms[:5])
require.NoError(t, err)
require.False(t, matches)
// Extra/different permissions should NOT match exactly.
differentPerms := append(
expectedPerms,
bakery.Op{Entity: "invalid", Action: "write"},
)
matches, err = MacaroonMatchesPermissions(path, differentPerms)
require.NoError(t, err)
require.False(t, matches)
}
// TestHasMacaroonSuffix tests that HasMacaroonSuffix correctly
// checks the suffix of the super macaroon path.
func TestHasMacaroonSuffix(t *testing.T) {
t.Parallel()
tests := []struct {
name string
path string
wantErr bool
errStr string
}{
{
name: "empty path",
path: "",
wantErr: true,
errStr: "super-macaroon-path cannot be empty",
},
{
name: "valid path",
path: "/tmp/test.macaroon",
wantErr: false,
},
{
name: "invalid path - missing suffix",
path: "/tmp/test.mac",
wantErr: true,
errStr: "super-macaroon-path must end " +
"with the .macaroon suffix",
},
{
name: "invalid path - wrong suffix",
path: "/tmp/test.macaroon.tmp",
wantErr: true,
errStr: "super-macaroon-path must end " +
"with the .macaroon suffix",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := HasMacaroonSuffix(tt.path)
if tt.wantErr {
require.Error(t, err)
require.Contains(t, err.Error(), tt.errStr)
} else {
require.NoError(t, err)
}
})
}
}