Skip to content

Commit edf195e

Browse files
committed
firewall: changes to initial structure
1 parent f1d65e5 commit edf195e

File tree

4 files changed

+75
-54
lines changed

4 files changed

+75
-54
lines changed

firewall/caveats.go

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,20 @@ type InterceptMetaInfo struct {
5252
// that is issuing this request.
5353
ActorName string `json:"actor_name"`
5454

55+
// Feature is the feature that caused the actor to execute this action.
56+
Feature string `json:"feature"`
57+
5558
// Trigger is the action or condition that triggered this intercepted
5659
// request to be made.
5760
Trigger string `json:"trigger"`
5861

5962
// Intent is the desired outcome or end condition this request aims to
6063
// arrive at.
6164
Intent string `json:"intent"`
65+
66+
// StructuredJsonData is extra, structured, info that the Autopilot can
67+
// send to Lit. It is a json serialised string.
68+
StructuredJsonData string `json:"structured_json_data"`
6269
}
6370

6471
// ToCaveat returns the full custom caveat string representation of the
@@ -96,23 +103,24 @@ func ParseMetaInfoCaveat(caveat string) (*InterceptMetaInfo, error) {
96103
return i, nil
97104
}
98105

99-
// InterceptRule is the JSON serializable struct containing all the rules and
106+
// InterceptRules is the JSON serializable struct containing all the rules and
100107
// their limits/settings that need to be enforced on a request made by an
101108
// automated node management software against LiT. The rule information is added
102109
// as a custom macaroon caveat.
103-
type InterceptRule struct {
104-
// Name is the name of the rule. It must correspond to a
105-
Name string `json:"name"`
106-
107-
// Restrictions is a key/value map of all the parameters that apply to
108-
// this rule.
109-
Restrictions map[string]string `json:"restrictions"`
110+
type InterceptRules struct {
111+
// SessionRules are rules that apply session wide. The map is rule
112+
// name to rule value.
113+
SessionRules map[string]string `json:"session_rules"`
114+
115+
// Feature rules are rules that apply to a specific feature. The map is
116+
// feature name to a map of rule name to rule value.
117+
FeatureRules map[string]map[string]string `json:"feature_rules"`
110118
}
111119

112120
// RulesToCaveat encodes a list of rules as a full custom caveat string
113121
// representation in this format:
114122
// lnd-custom lit-mac-fw rules:[<array_of_JSON_encoded_rules>]
115-
func RulesToCaveat(rules []*InterceptRule) (string, error) {
123+
func RulesToCaveat(rules *InterceptRules) (string, error) {
116124
jsonBytes, err := json.Marshal(rules)
117125
if err != nil {
118126
return "", fmt.Errorf("error JSON marshaling: %v", err)
@@ -122,7 +130,7 @@ func RulesToCaveat(rules []*InterceptRule) (string, error) {
122130
}
123131

124132
// ParseRuleCaveat tries to parse the given caveat string as a rule struct.
125-
func ParseRuleCaveat(caveat string) ([]*InterceptRule, error) {
133+
func ParseRuleCaveat(caveat string) (*InterceptRules, error) {
126134
if !strings.HasPrefix(caveat, MetaRulesFullCaveatPrefix) {
127135
return nil, ErrNoRulesCaveat
128136
}
@@ -134,11 +142,11 @@ func ParseRuleCaveat(caveat string) ([]*InterceptRule, error) {
134142

135143
// There's a colon after the prefix that we need to skip as well.
136144
jsonData := caveat[len(MetaRulesFullCaveatPrefix)+1:]
137-
var rules []*InterceptRule
145+
var rules InterceptRules
138146

139147
if err := json.Unmarshal([]byte(jsonData), &rules); err != nil {
140148
return nil, fmt.Errorf("error unmarshaling JSON: %v", err)
141149
}
142150

143-
return rules, nil
151+
return &rules, nil
144152
}

firewall/caveats_test.go

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,27 @@ import (
99

1010
const (
1111
testMetaCaveat = "lnd-custom lit-mac-fw meta:{\"actor_name\":" +
12-
"\"re-balancer\",\"trigger\":\"channel 7413345453234435345 " +
13-
"depleted\",\"intent\":\"increase outbound liquidity by " +
14-
"2000000 sats\"}"
15-
16-
testRulesCaveat = "lnd-custom lit-mac-fw rules:[{\"name\":" +
17-
"\"re-balance-limits\",\"restrictions\":" +
18-
"{\"first-hop-ignore-list\":\"03abcd...,02badb01...\"," +
19-
"\"max-hops\":\"4\",\"off-chain-fees-sats\":\"10\"}}," +
20-
"{\"name\":\"time-limits\",\"restrictions\":" +
21-
"{\"re-balance-min-interval-seconds\":\"3600\"}}]"
12+
"\"autopilot\",\"feature\":\"re-balance\",\"trigger\":" +
13+
"\"channel 7413345453234435345 depleted\",\"intent\":" +
14+
"\"increase outbound liquidity by 2000000 sats\"," +
15+
"\"structured_json_data\":\"{}\"}"
16+
17+
testRulesCaveat = "lnd-custom lit-mac-fw rules:{\"session_rules\":{" +
18+
"\"rate-limit\":\"1/10\"},\"feature_rules\":{\"AutoFees\":{" +
19+
"\"first-hop-ignore-list\":\"03abcd...,02badb01...\"," +
20+
"\"max-hops\":\"4\"},\"Rebalance\":{\"off-chain-fees-sats\":" +
21+
"\"10\",\"re-balance-min-interval-seconds\":\"3600\"}}}"
2222
)
2323

2424
// TestInterceptMetaInfo makes sure that a meta information struct can be
2525
// formatted as a caveat and then parsed again successfully.
2626
func TestInterceptMetaInfo(t *testing.T) {
2727
info := &InterceptMetaInfo{
28-
ActorName: "re-balancer",
29-
Trigger: "channel 7413345453234435345 depleted",
30-
Intent: "increase outbound liquidity by 2000000 sats",
28+
ActorName: "autopilot",
29+
Feature: "re-balance",
30+
Trigger: "channel 7413345453234435345 depleted",
31+
Intent: "increase outbound liquidity by 2000000 sats",
32+
StructuredJsonData: "{}",
3133
}
3234

3335
caveat, err := info.ToCaveat()
@@ -90,19 +92,21 @@ func TestParseMetaInfoCaveat(t *testing.T) {
9092
// TestInterceptRule makes sure that a rules list struct can be formatted as a
9193
// caveat and then parsed again successfully.
9294
func TestInterceptRule(t *testing.T) {
93-
rules := []*InterceptRule{{
94-
Name: "re-balance-limits",
95-
Restrictions: map[string]string{
96-
"off-chain-fees-sats": "10",
97-
"max-hops": "4",
98-
"first-hop-ignore-list": "03abcd...,02badb01...",
95+
rules := &InterceptRules{
96+
FeatureRules: map[string]map[string]string{
97+
"AutoFees": {
98+
"first-hop-ignore-list": "03abcd...,02badb01...",
99+
"max-hops": "4",
100+
},
101+
"Rebalance": {
102+
"off-chain-fees-sats": "10",
103+
"re-balance-min-interval-seconds": "3600",
104+
},
99105
},
100-
}, {
101-
Name: "time-limits",
102-
Restrictions: map[string]string{
103-
"re-balance-min-interval-seconds": "3600",
106+
SessionRules: map[string]string{
107+
"rate-limit": "1/10",
104108
},
105-
}}
109+
}
106110

107111
caveat, err := RulesToCaveat(rules)
108112
require.NoError(t, err)
@@ -122,7 +126,7 @@ func TestParseRulesCaveat(t *testing.T) {
122126
name string
123127
input string
124128
err error
125-
result []*InterceptRule
129+
result *InterceptRules
126130
}{{
127131
name: "empty string",
128132
input: "",
@@ -138,23 +142,25 @@ func TestParseRulesCaveat(t *testing.T) {
138142
"'b' looking for beginning of value"),
139143
}, {
140144
name: "empty JSON",
141-
input: "lnd-custom lit-mac-fw rules:[]",
142-
result: []*InterceptRule{},
143-
}, {
144-
name: "empty rules",
145-
input: "lnd-custom lit-mac-fw rules:[{}, {}]",
146-
result: []*InterceptRule{{}, {}},
145+
input: "lnd-custom lit-mac-fw rules:{}",
146+
result: &InterceptRules{},
147147
}, {
148148
name: "valid rules",
149-
input: "lnd-custom lit-mac-fw rules:[{\"name\":\"foo\"}, " +
150-
"{\"restrictions\":{\"foo\":\"bar\"}}]",
151-
result: []*InterceptRule{{
152-
Name: "foo",
153-
}, {
154-
Restrictions: map[string]string{
155-
"foo": "bar",
149+
input: "lnd-custom lit-mac-fw rules:{\"session_rules\":" +
150+
"{\"rate-limit\":\"2000\"}, \"feature_rules\":" +
151+
"{\"Autofees\":{\"foo\":\"bar\", \"rate-limit\":" +
152+
"\"1000\"}}}",
153+
result: &InterceptRules{
154+
FeatureRules: map[string]map[string]string{
155+
"Autofees": {
156+
"foo": "bar",
157+
"rate-limit": "1000",
158+
},
156159
},
157-
}},
160+
SessionRules: map[string]string{
161+
"rate-limit": "2000",
162+
},
163+
},
158164
}}
159165

160166
for _, tc := range testCases {

firewall/request_info.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ type RequestInfo struct {
3030
MWRequestType string
3131
URI string
3232
GRPCMessageType string
33+
IsError bool
34+
Serialized []byte
3335
Streaming bool
3436
Macaroon *macaroon.Macaroon
3537
Caveats []string
3638
MetaInfo *InterceptMetaInfo
37-
Rules []*InterceptRule
39+
Rules *InterceptRules
3840
}
3941

4042
// NewInfoFromRequest parses the given RPC middleware interception request and
@@ -54,6 +56,8 @@ func NewInfoFromRequest(req *lnrpc.RPCMiddlewareRequest) (*RequestInfo, error) {
5456
MWRequestType: MWRequestTypeRequest,
5557
URI: t.Request.MethodFullUri,
5658
GRPCMessageType: t.Request.TypeName,
59+
IsError: t.Request.IsError,
60+
Serialized: t.Request.Serialized,
5761
Streaming: t.Request.StreamRpc,
5862
}
5963

@@ -62,6 +66,8 @@ func NewInfoFromRequest(req *lnrpc.RPCMiddlewareRequest) (*RequestInfo, error) {
6266
MWRequestType: MWRequestTypeResponse,
6367
URI: t.Response.MethodFullUri,
6468
GRPCMessageType: t.Response.TypeName,
69+
IsError: t.Response.IsError,
70+
Serialized: t.Response.Serialized,
6571
Streaming: t.Response.StreamRpc,
6672
}
6773

firewall/rule_enforcer.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ func (r *RuleEnforcer) Intercept(_ context.Context,
5353
log.Infof("Enforcing rule %v", ri)
5454

5555
// Enforce actual rules.
56-
if len(ri.Rules) > 0 {
56+
numRules := len(ri.Rules.SessionRules) + len(ri.Rules.FeatureRules)
57+
if numRules > 0 {
5758
// TODO(guggero): Implement rules and their enforcement.
58-
log.Debugf("There are %d rules to enforce", len(ri.Rules))
59+
log.Debugf("There are %d rules to enforce", numRules)
5960
}
6061

6162
// Send empty response, accepting the request.

0 commit comments

Comments
 (0)