Skip to content

Commit 3561e26

Browse files
committed
feat: add UrlPathRule
1 parent 87936ab commit 3561e26

File tree

4 files changed

+107
-9
lines changed

4 files changed

+107
-9
lines changed

rule/rule.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ func CheckRules(ruleIds []string, r *http.Request) (*RuleResult, error) {
4242
switch rule.Type {
4343
case "User-Agent":
4444
ruleObj = &UaRule{}
45+
case "URL Path":
46+
ruleObj = &UrlPathRule{}
4547
case "IP":
4648
ruleObj = &IpRule{}
4749
case "WAF":

rule/rule_url_path.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2024 The casbin Authors. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package rule
16+
17+
import (
18+
"fmt"
19+
"net/http"
20+
"regexp"
21+
"strings"
22+
23+
"github.com/casbin/caswaf/object"
24+
)
25+
26+
type UrlPathRule struct{}
27+
28+
func (r *UrlPathRule) checkRule(expressions []*object.Expression, req *http.Request) (*RuleResult, error) {
29+
path := req.URL.Path
30+
for _, expression := range expressions {
31+
pattern := expression.Value
32+
reason := fmt.Sprintf("expression matched: \"%s %s %s\"", path, expression.Operator, expression.Value)
33+
switch expression.Operator {
34+
case "contains":
35+
if strings.Contains(path, pattern) {
36+
return &RuleResult{Reason: reason}, nil
37+
}
38+
case "does not contain":
39+
if !strings.Contains(path, pattern) {
40+
return &RuleResult{Reason: reason}, nil
41+
}
42+
case "equals":
43+
if path == pattern {
44+
return &RuleResult{Reason: reason}, nil
45+
}
46+
case "does not equal":
47+
if strings.Compare(path, pattern) != 0 {
48+
return &RuleResult{Reason: reason}, nil
49+
}
50+
case "match":
51+
isHit, err := regexp.MatchString(pattern, path)
52+
if err != nil {
53+
return nil, err
54+
}
55+
if isHit {
56+
return &RuleResult{Reason: reason}, nil
57+
}
58+
}
59+
}
60+
61+
return nil, nil
62+
}

web/src/RuleEditPage.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ class RuleEditPage extends React.Component {
9999
{value: "WAF", text: "WAF"},
100100
{value: "IP", text: "IP"},
101101
{value: "User-Agent", text: "User-Agent"},
102+
{value: "URL Path", text: "URL Path"},
102103
{value: "IP Rate Limiting", text: i18next.t("rule:IP Rate Limiting")},
103104
{value: "Compound", text: i18next.t("rule:Compound")},
104105
].map((item, index) => <Option key={index} value={item.value}>{item.text}</Option>)
@@ -144,6 +145,18 @@ class RuleEditPage extends React.Component {
144145
/>
145146
) : null
146147
}
148+
{
149+
this.state.rule.type === "URL Path" ? (
150+
<UaRuleTable
151+
kind="urlPath"
152+
title={"URL Paths"}
153+
table={this.state.rule.expressions}
154+
ruleName={this.state.rule.name}
155+
account={this.props.account}
156+
onUpdateTable={(value) => {this.updateRuleField("expressions", value);}}
157+
/>
158+
) : null
159+
}
147160
{
148161
this.state.rule.type === "IP Rate Limiting" ? (
149162
<IpRateRuleTable

web/src/components/UaRuleTable.js

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,31 @@ class UaRuleTable extends React.Component {
2525
super(props);
2626
this.state = {
2727
classes: props,
28-
defaultRules: [
29-
{
30-
name: "Current User-Agent",
31-
operator: "equals",
32-
value: window.navigator.userAgent,
33-
},
34-
],
3528
};
3629
if (this.props.table.length === 0) {
3730
this.restore();
3831
}
3932
}
4033

34+
getDefaultRules() {
35+
if (this.props.kind === "urlPath") {
36+
return [
37+
{
38+
name: "Example",
39+
operator: "contains",
40+
value: "/.git/config",
41+
},
42+
];
43+
}
44+
return [
45+
{
46+
name: "Current User-Agent",
47+
operator: "equals",
48+
value: window.navigator.userAgent,
49+
},
50+
];
51+
}
52+
4153
updateTable(table) {
4254
this.props.onUpdateTable(table);
4355
}
@@ -48,7 +60,12 @@ class UaRuleTable extends React.Component {
4860
}
4961

5062
addRow(table) {
51-
const row = {name: `New UA Rule - ${table.length}`, operator: "equals", value: ""};
63+
const isPath = this.props.kind === "urlPath";
64+
const row = {
65+
name: isPath ? `New URL Path Rule - ${table.length}` : `New UA Rule - ${table.length}`,
66+
operator: isPath ? "contains" : "equals",
67+
value: "",
68+
};
5269
if (table === undefined) {
5370
table = [];
5471
}
@@ -73,7 +90,7 @@ class UaRuleTable extends React.Component {
7390
}
7491

7592
restore() {
76-
this.updateTable(this.state.defaultRules);
93+
this.updateTable(this.getDefaultRules());
7794
}
7895

7996
renderTable(table) {
@@ -169,4 +186,8 @@ class UaRuleTable extends React.Component {
169186
}
170187
}
171188

189+
UaRuleTable.defaultProps = {
190+
kind: "userAgent",
191+
};
192+
172193
export default UaRuleTable;

0 commit comments

Comments
 (0)