Skip to content

Commit 9bcee65

Browse files
committed
accounts: add an IDFromCaveates helper
And use that from the existing accountFromMacaroon helper (which will then test the new helper by proxy). We add this helper so that we can use it later on from the sessions package where we want to extract an account ID from a caveat (we wont have a full macaroon available).
1 parent 565ebe8 commit 9bcee65

File tree

1 file changed

+57
-9
lines changed

1 file changed

+57
-9
lines changed

accounts/interceptor.go

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package accounts
22

33
import (
4+
"bytes"
45
"context"
56
"encoding/hex"
67
"errors"
78
"fmt"
9+
"strings"
810

911
mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware"
12+
"github.com/lightningnetwork/lnd/fn"
1013
"github.com/lightningnetwork/lnd/lnrpc"
1114
"github.com/lightningnetwork/lnd/macaroons"
1215
"google.golang.org/protobuf/proto"
@@ -23,6 +26,15 @@ const (
2326
accountMiddlewareName = "lit-account"
2427
)
2528

29+
var (
30+
// caveatPrefix is the prefix that is used for custom caveats that are
31+
// used by the account system. This prefix is used to identify the
32+
// custom caveat and extract the condition (the AccountID) from it.
33+
caveatPrefix = []byte(fmt.Sprintf(
34+
"%s %s ", macaroons.CondLndCustom, CondAccount,
35+
))
36+
)
37+
2638
// Name returns the name of the interceptor.
2739
func (s *InterceptorService) Name() string {
2840
return accountMiddlewareName
@@ -199,22 +211,58 @@ func parseRPCMessage(msg *lnrpc.RPCMessage) (proto.Message, error) {
199211
// accountFromMacaroon attempts to extract an account ID from the custom account
200212
// caveat in the macaroon.
201213
func accountFromMacaroon(mac *macaroon.Macaroon) (*AccountID, error) {
202-
// Extract the account caveat from the macaroon.
203-
macaroonAccount := macaroons.GetCustomCaveatCondition(mac, CondAccount)
204-
if macaroonAccount == "" {
205-
// There is no condition that locks the macaroon to an account,
206-
// so there is nothing to check.
214+
if mac == nil {
207215
return nil, nil
208216
}
209217

210-
// The macaroon is indeed locked to an account. Fetch the account and
211-
// validate its balance.
212-
accountIDBytes, err := hex.DecodeString(macaroonAccount)
218+
// Extract the account caveat from the macaroon.
219+
accountID, err := IDFromCaveats(mac.Caveats())
213220
if err != nil {
214221
return nil, err
215222
}
216223

224+
var id *AccountID
225+
accountID.WhenSome(func(aID AccountID) {
226+
id = &aID
227+
})
228+
229+
return id, nil
230+
}
231+
232+
// IDFromCaveats attempts to extract an AccountID from the given set of caveats
233+
// by looking for the custom caveat that binds a macaroon to a certain account.
234+
func IDFromCaveats(caveats []macaroon.Caveat) (fn.Option[AccountID], error) {
235+
var accountIDStr string
236+
for _, caveat := range caveats {
237+
// The caveat id has a format of
238+
// "lnd-custom [custom-caveat-name] [custom-caveat-condition]"
239+
// and we only want the condition part. If we match the prefix
240+
// part we return the condition that comes after the prefix.
241+
if bytes.HasPrefix(caveat.Id, caveatPrefix) {
242+
caveatSplit := strings.SplitN(
243+
string(caveat.Id),
244+
string(caveatPrefix),
245+
2,
246+
)
247+
if len(caveatSplit) == 2 {
248+
accountIDStr = caveatSplit[1]
249+
250+
break
251+
}
252+
}
253+
}
254+
255+
if accountIDStr == "" {
256+
return fn.None[AccountID](), nil
257+
}
258+
217259
var accountID AccountID
260+
accountIDBytes, err := hex.DecodeString(accountIDStr)
261+
if err != nil {
262+
return fn.None[AccountID](), err
263+
}
264+
218265
copy(accountID[:], accountIDBytes)
219-
return &accountID, nil
266+
267+
return fn.Some(accountID), nil
220268
}

0 commit comments

Comments
 (0)