mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
In this commit, we update our various firewall interceptors so that they rely on the session ID passed via gRPC metadata to extract a session ID. For the PrivacyMapper and RuleEnforcer, these _MUST_ always contain a session ID and so we error out if one was not found. For the request logger, the session ID is optional and so we pass it to the new SessionID field in the AddActionReq - our bbolt actions DB will not make use of this field on persistence (but our incoming SQL version will).
154 lines
4.2 KiB
Go
154 lines
4.2 KiB
Go
package firewall
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/lightninglabs/lightning-terminal/session"
|
|
"github.com/lightningnetwork/lnd/fn"
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
"google.golang.org/grpc/metadata"
|
|
"gopkg.in/macaroon.v2"
|
|
)
|
|
|
|
const (
|
|
// MWRequestTypeStreamAuth represents the type name for a stream
|
|
// authentication interception message.
|
|
MWRequestTypeStreamAuth = "stream_auth"
|
|
|
|
// MWRequestTypeRequest represents the type name for a request
|
|
// interception message.
|
|
MWRequestTypeRequest = "request"
|
|
|
|
// MWRequestTypeResponse represents the type name for a response
|
|
// interception message.
|
|
MWRequestTypeResponse = "response"
|
|
)
|
|
|
|
// RequestInfo stores the parsed representation of an incoming RPC middleware
|
|
// request.
|
|
type RequestInfo struct {
|
|
SessionID fn.Option[session.ID]
|
|
MsgID uint64
|
|
RequestID uint64
|
|
MWRequestType string
|
|
URI string
|
|
GRPCMessageType string
|
|
IsError bool
|
|
Serialized []byte
|
|
Streaming bool
|
|
Macaroon *macaroon.Macaroon
|
|
Caveats []string
|
|
MetaInfo *InterceptMetaInfo
|
|
Rules *InterceptRules
|
|
WithPrivacy bool
|
|
}
|
|
|
|
// NewInfoFromRequest parses the given RPC middleware interception request and
|
|
// returns a RequestInfo struct.
|
|
func NewInfoFromRequest(req *lnrpc.RPCMiddlewareRequest) (*RequestInfo, error) {
|
|
var ri *RequestInfo
|
|
switch t := req.InterceptType.(type) {
|
|
case *lnrpc.RPCMiddlewareRequest_StreamAuth:
|
|
ri = &RequestInfo{
|
|
MWRequestType: MWRequestTypeStreamAuth,
|
|
URI: t.StreamAuth.MethodFullUri,
|
|
Streaming: true,
|
|
}
|
|
|
|
case *lnrpc.RPCMiddlewareRequest_Request:
|
|
ri = &RequestInfo{
|
|
MWRequestType: MWRequestTypeRequest,
|
|
URI: t.Request.MethodFullUri,
|
|
GRPCMessageType: t.Request.TypeName,
|
|
IsError: t.Request.IsError,
|
|
Serialized: t.Request.Serialized,
|
|
Streaming: t.Request.StreamRpc,
|
|
}
|
|
|
|
case *lnrpc.RPCMiddlewareRequest_Response:
|
|
ri = &RequestInfo{
|
|
MWRequestType: MWRequestTypeResponse,
|
|
URI: t.Response.MethodFullUri,
|
|
GRPCMessageType: t.Response.TypeName,
|
|
IsError: t.Response.IsError,
|
|
Serialized: t.Response.Serialized,
|
|
Streaming: t.Response.StreamRpc,
|
|
}
|
|
|
|
default:
|
|
return nil, fmt.Errorf("invalid request type: %T", t)
|
|
}
|
|
|
|
md := make(metadata.MD)
|
|
for k, vs := range req.MetadataPairs {
|
|
for _, v := range vs.Values {
|
|
md.Append(k, v)
|
|
}
|
|
}
|
|
|
|
sessionID, err := session.FromGRPCMetadata(md)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error extracting session ID "+
|
|
"from request: %v", err)
|
|
}
|
|
|
|
ri.MsgID = req.MsgId
|
|
ri.RequestID = req.RequestId
|
|
ri.SessionID = sessionID
|
|
|
|
// If there is no macaroon in the request, then there is nothing left
|
|
// to parse.
|
|
if len(req.RawMacaroon) == 0 {
|
|
return ri, nil
|
|
}
|
|
|
|
ri.Macaroon = &macaroon.Macaroon{}
|
|
if err := ri.Macaroon.UnmarshalBinary(req.RawMacaroon); err != nil {
|
|
return nil, fmt.Errorf("error parsing macaroon: %v", err)
|
|
}
|
|
|
|
ri.Caveats = make([]string, len(ri.Macaroon.Caveats()))
|
|
for idx, cav := range ri.Macaroon.Caveats() {
|
|
ri.Caveats[idx] = string(cav.Id)
|
|
|
|
// Apply any meta information sent as a custom caveat. Only the
|
|
// last one will be considered if there are multiple caveats.
|
|
metaInfo, err := ParseMetaInfoCaveat(ri.Caveats[idx])
|
|
if err == nil {
|
|
ri.MetaInfo = metaInfo
|
|
|
|
// The same caveat can't be a meta info and a rule list
|
|
// or a privacy caveat.
|
|
continue
|
|
}
|
|
|
|
// Also apply the rule list sent as a custom caveat. Only the
|
|
// last set of rules will be considered if there are multiple
|
|
// caveats.
|
|
rules, err := ParseRuleCaveat(ri.Caveats[idx])
|
|
if err == nil {
|
|
ri.Rules = rules
|
|
|
|
// The same caveat can't be a rule list and a privacy
|
|
// caveat.
|
|
continue
|
|
}
|
|
|
|
if IsPrivacyCaveat(ri.Caveats[idx]) {
|
|
ri.WithPrivacy = true
|
|
}
|
|
}
|
|
|
|
return ri, nil
|
|
}
|
|
|
|
// String returns the string representation of the request info struct.
|
|
func (ri *RequestInfo) String() string {
|
|
return fmt.Sprintf("Request={msg_id=%d, request_id=%d, type=%v, "+
|
|
"uri=%v, grpc_message_type=%v, streaming=%v, caveats=[%v], "+
|
|
"meta_info=%v, rules=[%v]}",
|
|
ri.MsgID, ri.RequestID, ri.MWRequestType, ri.URI,
|
|
ri.GRPCMessageType, ri.Streaming, strings.Join(ri.Caveats, ","),
|
|
ri.MetaInfo, ri.Rules)
|
|
}
|