@@ -5,11 +5,14 @@ import (
55 "encoding/hex"
66 "errors"
77 "fmt"
8+ "strings"
89
910 mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware"
11+ "github.com/lightningnetwork/lnd/fn"
1012 "github.com/lightningnetwork/lnd/lnrpc"
1113 "github.com/lightningnetwork/lnd/macaroons"
1214 "google.golang.org/protobuf/proto"
15+ "gopkg.in/macaroon-bakery.v2/bakery/checkers"
1316 "gopkg.in/macaroon.v2"
1417)
1518
@@ -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.
2739func (s * InterceptorService ) Name () string {
2840 return accountMiddlewareName
@@ -199,22 +211,64 @@ 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.
201213func 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+ // CaveatFromID creates a custom caveat that can be used to bind a macaroon to
233+ // a certain account.
234+ func CaveatFromID (id AccountID ) macaroon.Caveat {
235+ condition := checkers .Condition (macaroons .CondLndCustom , fmt .Sprintf (
236+ "%s %x" , CondAccount , id [:],
237+ ))
238+
239+ return macaroon.Caveat {Id : []byte (condition )}
240+ }
241+
242+ // IDFromCaveats attempts to extract an AccountID from the given set of caveats
243+ // by looking for the custom caveat that binds a macaroon to a certain account.
244+ func IDFromCaveats (caveats []macaroon.Caveat ) (fn.Option [AccountID ], error ) {
245+ var accountIDStr string
246+ for _ , caveat := range caveats {
247+ // The caveat id has a format of
248+ // "lnd-custom [custom-caveat-name] [custom-caveat-condition]"
249+ // and we only want the condition part. If we match the prefix
250+ // part we return the condition that comes after the prefix.
251+ _ , after , found := strings .Cut (
252+ string (caveat .Id ), string (caveatPrefix ),
253+ )
254+ if ! found {
255+ continue
256+ }
257+
258+ accountIDStr = after
259+ }
260+
261+ if accountIDStr == "" {
262+ return fn .None [AccountID ](), nil
263+ }
264+
217265 var accountID AccountID
266+ accountIDBytes , err := hex .DecodeString (accountIDStr )
267+ if err != nil {
268+ return fn .None [AccountID ](), err
269+ }
270+
218271 copy (accountID [:], accountIDBytes )
219- return & accountID , nil
272+
273+ return fn .Some (accountID ), nil
220274}
0 commit comments