mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
multi: make request logger level configurable
This commit is contained in:
parent
2d57c25850
commit
8e61eb90da
4 changed files with 131 additions and 32 deletions
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/lightninglabs/faraday/chain"
|
||||
"github.com/lightninglabs/faraday/frdrpcserver"
|
||||
"github.com/lightninglabs/lightning-terminal/autopilotserver"
|
||||
"github.com/lightninglabs/lightning-terminal/firewall"
|
||||
mid "github.com/lightninglabs/lightning-terminal/rpcmiddleware"
|
||||
"github.com/lightninglabs/lndclient"
|
||||
"github.com/lightninglabs/loop/loopd"
|
||||
|
|
@ -188,6 +189,8 @@ type Config struct {
|
|||
|
||||
Autopilot *autopilotserver.Config `group:"Autopilot server options" namespace:"autopilot"`
|
||||
|
||||
Firewall *firewall.Config `group:"Firewall options" namespace:"firewall"`
|
||||
|
||||
// faradayRpcConfig is a subset of faraday's full configuration that is
|
||||
// passed into faraday's RPC server.
|
||||
faradayRpcConfig *frdrpcserver.Config
|
||||
|
|
@ -331,6 +334,7 @@ func defaultConfig() *Config {
|
|||
Autopilot: &autopilotserver.Config{
|
||||
PingCadence: time.Hour,
|
||||
},
|
||||
Firewall: firewall.DefaultConfig(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
20
firewall/config.go
Normal file
20
firewall/config.go
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package firewall
|
||||
|
||||
// Config holds all config options for the firewall.
|
||||
type Config struct {
|
||||
RequestLogger *RequestLoggerConfig `group:"request-logger" namespace:"request-logger" description:"request logger settings"`
|
||||
}
|
||||
|
||||
// RequestLoggerConfig holds all the config options for the request logger.
|
||||
type RequestLoggerConfig struct {
|
||||
RequestLoggerLevel RequestLoggerLevel `long:"level" description:"Set the request logger level. Options include 'all', 'full' and 'interceptor''"`
|
||||
}
|
||||
|
||||
// DefaultConfig constructs the default firewall Config struct.
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
RequestLogger: &RequestLoggerConfig{
|
||||
RequestLoggerLevel: RequestLoggerLevelInterceptor,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package firewall
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
|
@ -12,6 +13,7 @@ import (
|
|||
"github.com/lightninglabs/lightning-terminal/session"
|
||||
"github.com/lightninglabs/protobuf-hex-display/jsonpb"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -35,10 +37,20 @@ var (
|
|||
_ mid.RequestInterceptor = (*RequestLogger)(nil)
|
||||
)
|
||||
|
||||
type RequestLoggerLevel string
|
||||
|
||||
const (
|
||||
RequestLoggerLevelInterceptor = "interceptor"
|
||||
RequestLoggerLevelAll = "all"
|
||||
RequestLoggerLevelFull = "full"
|
||||
)
|
||||
|
||||
// RequestLogger is a RequestInterceptor that just logs incoming RPC requests.
|
||||
type RequestLogger struct {
|
||||
actionsDB firewalldb.ActionsWriteDB
|
||||
|
||||
shouldLogAction func(ri *RequestInfo) (bool, bool)
|
||||
|
||||
// reqIDToAction is a map from request ID to an ActionLocator that can
|
||||
// be used to find the corresponding action. This is used so that
|
||||
// requests and responses can be easily linked. The mu mutex must be
|
||||
|
|
@ -48,11 +60,55 @@ type RequestLogger struct {
|
|||
}
|
||||
|
||||
// NewRequestLogger creates a new RequestLogger.
|
||||
func NewRequestLogger(actionsDB firewalldb.ActionsWriteDB) *RequestLogger {
|
||||
return &RequestLogger{
|
||||
actionsDB: actionsDB,
|
||||
reqIDToAction: make(map[uint64]*firewalldb.ActionLocator),
|
||||
func NewRequestLogger(cfg *RequestLoggerConfig,
|
||||
actionsDB firewalldb.ActionsWriteDB) (*RequestLogger, error) {
|
||||
|
||||
hasInterceptorCaveat := func(caveats []string) bool {
|
||||
for _, c := range caveats {
|
||||
if strings.HasPrefix(c, macaroons.CondLndCustom) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var shouldLogAction func(ri *RequestInfo) (bool, bool)
|
||||
switch cfg.RequestLoggerLevel {
|
||||
// Only log requests that have an interceptor caveat attached.
|
||||
case RequestLoggerLevelInterceptor:
|
||||
shouldLogAction = func(ri *RequestInfo) (bool, bool) {
|
||||
if hasInterceptorCaveat(ri.Caveats) {
|
||||
return true, true
|
||||
}
|
||||
|
||||
return false, false
|
||||
}
|
||||
|
||||
// Log all requests but only log request params if the request
|
||||
// has an interceptor caveat.
|
||||
case RequestLoggerLevelAll:
|
||||
shouldLogAction = func(ri *RequestInfo) (bool, bool) {
|
||||
return true, hasInterceptorCaveat(ri.Caveats)
|
||||
}
|
||||
|
||||
// Log all requests will all request parameters.
|
||||
case RequestLoggerLevelFull:
|
||||
shouldLogAction = func(ri *RequestInfo) (bool, bool) {
|
||||
return true, true
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown request logger level: %s. "+
|
||||
"Expected either 'interceptor', 'all' or 'full'",
|
||||
cfg.RequestLoggerLevel)
|
||||
}
|
||||
|
||||
return &RequestLogger{
|
||||
shouldLogAction: shouldLogAction,
|
||||
actionsDB: actionsDB,
|
||||
reqIDToAction: make(map[uint64]*firewalldb.ActionLocator),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Name returns the name of the interceptor.
|
||||
|
|
@ -89,6 +145,11 @@ func (r *RequestLogger) Intercept(_ context.Context,
|
|||
return mid.RPCOk(req)
|
||||
}
|
||||
|
||||
shouldLogAction, withPayloadData := r.shouldLogAction(ri)
|
||||
if !shouldLogAction {
|
||||
return mid.RPCOk(req)
|
||||
}
|
||||
|
||||
log.Tracef("RequestLogger: Intercepting %v", ri)
|
||||
|
||||
switch ri.MWRequestType {
|
||||
|
|
@ -97,7 +158,7 @@ func (r *RequestLogger) Intercept(_ context.Context,
|
|||
|
||||
// Parse incoming requests and act on them.
|
||||
case MWRequestTypeRequest:
|
||||
return mid.RPCErr(req, r.addNewAction(ri))
|
||||
return mid.RPCErr(req, r.addNewAction(ri, withPayloadData))
|
||||
|
||||
// Parse and possibly manipulate outgoing responses.
|
||||
case MWRequestTypeResponse:
|
||||
|
|
@ -120,7 +181,9 @@ func (r *RequestLogger) Intercept(_ context.Context,
|
|||
}
|
||||
|
||||
// addNewAction persists the new action to the db.
|
||||
func (r *RequestLogger) addNewAction(ri *RequestInfo) error {
|
||||
func (r *RequestLogger) addNewAction(ri *RequestInfo,
|
||||
withPayloadData bool) error {
|
||||
|
||||
// If no macaroon is provided, then an empty 4-byte array is used as the
|
||||
// session ID. Otherwise, the macaroon is used to derive a session ID.
|
||||
var sessionID [4]byte
|
||||
|
|
@ -132,34 +195,40 @@ func (r *RequestLogger) addNewAction(ri *RequestInfo) error {
|
|||
}
|
||||
}
|
||||
|
||||
msg, err := mid.ParseProtobuf(ri.GRPCMessageType, ri.Serialized)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonMarshaler := &jsonpb.Marshaler{
|
||||
EmitDefaults: true,
|
||||
OrigName: true,
|
||||
}
|
||||
|
||||
jsonStr, err := jsonMarshaler.MarshalToString(proto.MessageV1(msg))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to decode response: %v", err)
|
||||
}
|
||||
|
||||
action := &firewalldb.Action{
|
||||
RPCMethod: ri.URI,
|
||||
RPCParamsJson: []byte(jsonStr),
|
||||
AttemptedAt: time.Now(),
|
||||
State: firewalldb.ActionStateInit,
|
||||
RPCMethod: ri.URI,
|
||||
AttemptedAt: time.Now(),
|
||||
State: firewalldb.ActionStateInit,
|
||||
}
|
||||
|
||||
if ri.MetaInfo != nil {
|
||||
action.ActorName = ri.MetaInfo.ActorName
|
||||
action.FeatureName = ri.MetaInfo.Feature
|
||||
action.Trigger = ri.MetaInfo.Trigger
|
||||
action.Intent = ri.MetaInfo.Intent
|
||||
action.StructuredJsonData = ri.MetaInfo.StructuredJsonData
|
||||
if withPayloadData {
|
||||
msg, err := mid.ParseProtobuf(ri.GRPCMessageType, ri.Serialized)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonMarshaler := &jsonpb.Marshaler{
|
||||
EmitDefaults: true,
|
||||
OrigName: true,
|
||||
}
|
||||
|
||||
jsonStr, err := jsonMarshaler.MarshalToString(
|
||||
proto.MessageV1(msg),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to decode response: %v", err)
|
||||
}
|
||||
|
||||
action.RPCParamsJson = []byte(jsonStr)
|
||||
|
||||
meta := ri.MetaInfo
|
||||
if meta != nil {
|
||||
action.ActorName = meta.ActorName
|
||||
action.FeatureName = meta.Feature
|
||||
action.Trigger = meta.Trigger
|
||||
action.Intent = meta.Intent
|
||||
action.StructuredJsonData = meta.StructuredJsonData
|
||||
}
|
||||
}
|
||||
|
||||
id, err := r.actionsDB.AddAction(sessionID, action)
|
||||
|
|
|
|||
|
|
@ -727,7 +727,13 @@ func (g *LightningTerminal) startSubservers() error {
|
|||
}
|
||||
g.accountServiceStarted = true
|
||||
|
||||
requestLogger := firewall.NewRequestLogger(g.firewallDB)
|
||||
requestLogger, err := firewall.NewRequestLogger(
|
||||
g.cfg.Firewall.RequestLogger, g.firewallDB,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating new request logger")
|
||||
}
|
||||
|
||||
privacyMapper := firewall.NewPrivacyMapper(
|
||||
g.firewallDB.PrivacyDB, firewall.CryptoRandIntn,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue