11package accounts
22
33import (
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.
2739func (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.
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+ // 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