@@ -3,6 +3,7 @@ package firewall
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "strings"
6
7
"sync"
7
8
"time"
8
9
@@ -12,6 +13,7 @@ import (
12
13
"github.com/lightninglabs/lightning-terminal/session"
13
14
"github.com/lightninglabs/protobuf-hex-display/jsonpb"
14
15
"github.com/lightningnetwork/lnd/lnrpc"
16
+ "github.com/lightningnetwork/lnd/macaroons"
15
17
)
16
18
17
19
const (
@@ -35,10 +37,20 @@ var (
35
37
_ mid.RequestInterceptor = (* RequestLogger )(nil )
36
38
)
37
39
40
+ type RequestLoggerLevel string
41
+
42
+ const (
43
+ RequestLoggerLevelInterceptor = "interceptor"
44
+ RequestLoggerLevelAll = "all"
45
+ RequestLoggerLevelFull = "full"
46
+ )
47
+
38
48
// RequestLogger is a RequestInterceptor that just logs incoming RPC requests.
39
49
type RequestLogger struct {
40
50
actionsDB firewalldb.ActionsWriteDB
41
51
52
+ shouldLogAction func (ri * RequestInfo ) (bool , bool )
53
+
42
54
// reqIDToAction is a map from request ID to an ActionLocator that can
43
55
// be used to find the corresponding action. This is used so that
44
56
// requests and responses can be easily linked. The mu mutex must be
@@ -48,11 +60,55 @@ type RequestLogger struct {
48
60
}
49
61
50
62
// NewRequestLogger creates a new RequestLogger.
51
- func NewRequestLogger (actionsDB firewalldb.ActionsWriteDB ) * RequestLogger {
52
- return & RequestLogger {
53
- actionsDB : actionsDB ,
54
- reqIDToAction : make (map [uint64 ]* firewalldb.ActionLocator ),
63
+ func NewRequestLogger (cfg * RequestLoggerConfig ,
64
+ actionsDB firewalldb.ActionsWriteDB ) (* RequestLogger , error ) {
65
+
66
+ hasInterceptorCaveat := func (caveats []string ) bool {
67
+ for _ , c := range caveats {
68
+ if strings .HasPrefix (c , macaroons .CondLndCustom ) {
69
+ return true
70
+ }
71
+ }
72
+
73
+ return false
74
+ }
75
+
76
+ var shouldLogAction func (ri * RequestInfo ) (bool , bool )
77
+ switch cfg .RequestLoggerLevel {
78
+ // Only log requests that have an interceptor caveat attached.
79
+ case RequestLoggerLevelInterceptor :
80
+ shouldLogAction = func (ri * RequestInfo ) (bool , bool ) {
81
+ if hasInterceptorCaveat (ri .Caveats ) {
82
+ return true , true
83
+ }
84
+
85
+ return false , false
86
+ }
87
+
88
+ // Log all requests but only log request params if the request
89
+ // has an interceptor caveat.
90
+ case RequestLoggerLevelAll :
91
+ shouldLogAction = func (ri * RequestInfo ) (bool , bool ) {
92
+ return true , hasInterceptorCaveat (ri .Caveats )
93
+ }
94
+
95
+ // Log all requests will all request parameters.
96
+ case RequestLoggerLevelFull :
97
+ shouldLogAction = func (ri * RequestInfo ) (bool , bool ) {
98
+ return true , true
99
+ }
100
+
101
+ default :
102
+ return nil , fmt .Errorf ("unknown request logger level: %s. " +
103
+ "Expected either 'interceptor', 'all' or 'full'" ,
104
+ cfg .RequestLoggerLevel )
55
105
}
106
+
107
+ return & RequestLogger {
108
+ shouldLogAction : shouldLogAction ,
109
+ actionsDB : actionsDB ,
110
+ reqIDToAction : make (map [uint64 ]* firewalldb.ActionLocator ),
111
+ }, nil
56
112
}
57
113
58
114
// Name returns the name of the interceptor.
@@ -89,6 +145,11 @@ func (r *RequestLogger) Intercept(_ context.Context,
89
145
return mid .RPCOk (req )
90
146
}
91
147
148
+ shouldLogAction , withPayloadData := r .shouldLogAction (ri )
149
+ if ! shouldLogAction {
150
+ return mid .RPCOk (req )
151
+ }
152
+
92
153
log .Tracef ("RequestLogger: Intercepting %v" , ri )
93
154
94
155
switch ri .MWRequestType {
@@ -97,7 +158,7 @@ func (r *RequestLogger) Intercept(_ context.Context,
97
158
98
159
// Parse incoming requests and act on them.
99
160
case MWRequestTypeRequest :
100
- return mid .RPCErr (req , r .addNewAction (ri ))
161
+ return mid .RPCErr (req , r .addNewAction (ri , withPayloadData ))
101
162
102
163
// Parse and possibly manipulate outgoing responses.
103
164
case MWRequestTypeResponse :
@@ -120,7 +181,9 @@ func (r *RequestLogger) Intercept(_ context.Context,
120
181
}
121
182
122
183
// addNewAction persists the new action to the db.
123
- func (r * RequestLogger ) addNewAction (ri * RequestInfo ) error {
184
+ func (r * RequestLogger ) addNewAction (ri * RequestInfo ,
185
+ withPayloadData bool ) error {
186
+
124
187
// If no macaroon is provided, then an empty 4-byte array is used as the
125
188
// session ID. Otherwise, the macaroon is used to derive a session ID.
126
189
var sessionID [4 ]byte
@@ -132,34 +195,40 @@ func (r *RequestLogger) addNewAction(ri *RequestInfo) error {
132
195
}
133
196
}
134
197
135
- msg , err := mid .ParseProtobuf (ri .GRPCMessageType , ri .Serialized )
136
- if err != nil {
137
- return err
198
+ action := & firewalldb.Action {
199
+ RPCMethod : ri .URI ,
200
+ AttemptedAt : time .Now (),
201
+ State : firewalldb .ActionStateInit ,
138
202
}
139
203
140
- jsonMarshaler := & jsonpb.Marshaler {
141
- EmitDefaults : true ,
142
- OrigName : true ,
143
- }
204
+ if withPayloadData {
205
+ msg , err := mid .ParseProtobuf (ri .GRPCMessageType , ri .Serialized )
206
+ if err != nil {
207
+ return err
208
+ }
144
209
145
- jsonStr , err := jsonMarshaler . MarshalToString ( proto . MessageV1 ( msg ))
146
- if err != nil {
147
- return fmt . Errorf ( "unable to decode response: %v" , err )
148
- }
210
+ jsonMarshaler := & jsonpb. Marshaler {
211
+ EmitDefaults : true ,
212
+ OrigName : true ,
213
+ }
149
214
150
- action := & firewalldb. Action {
151
- RPCMethod : ri . URI ,
152
- RPCParamsJson : [] byte ( jsonStr ),
153
- AttemptedAt : time . Now (),
154
- State : firewalldb . ActionStateInit ,
155
- }
215
+ jsonStr , err := jsonMarshaler . MarshalToString (
216
+ proto . MessageV1 ( msg ) ,
217
+ )
218
+ if err != nil {
219
+ return fmt . Errorf ( "unable to decode response: %v" , err )
220
+ }
156
221
157
- if ri .MetaInfo != nil {
158
- action .ActorName = ri .MetaInfo .ActorName
159
- action .FeatureName = ri .MetaInfo .Feature
160
- action .Trigger = ri .MetaInfo .Trigger
161
- action .Intent = ri .MetaInfo .Intent
162
- action .StructuredJsonData = ri .MetaInfo .StructuredJsonData
222
+ action .RPCParamsJson = []byte (jsonStr )
223
+
224
+ meta := ri .MetaInfo
225
+ if meta != nil {
226
+ action .ActorName = meta .ActorName
227
+ action .FeatureName = meta .Feature
228
+ action .Trigger = meta .Trigger
229
+ action .Intent = meta .Intent
230
+ action .StructuredJsonData = meta .StructuredJsonData
231
+ }
163
232
}
164
233
165
234
id , err := r .actionsDB .AddAction (sessionID , action )
0 commit comments