@@ -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