This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git
The following commit(s) were added to refs/heads/master by this push:
new 09f2400 feat: add UrlPathRule
09f2400 is described below
commit 09f2400d9bc822a67fcab220689bf870da4691a7
Author: Yang Luo <[email protected]>
AuthorDate: Sun Mar 29 21:23:34 2026 +0800
feat: add UrlPathRule
---
rule/rule.go | 2 ++
rule/rule_url_path.go | 62 +++++++++++++++++++++++++++++++++++++++
web/src/RuleEditPage.js | 13 ++++++++
web/src/components/UaRuleTable.js | 39 ++++++++++++++++++------
4 files changed, 107 insertions(+), 9 deletions(-)
diff --git a/rule/rule.go b/rule/rule.go
index 0468c3f..4c689da 100644
--- a/rule/rule.go
+++ b/rule/rule.go
@@ -42,6 +42,8 @@ func CheckRules(ruleIds []string, r *http.Request)
(*RuleResult, error) {
switch rule.Type {
case "User-Agent":
ruleObj = &UaRule{}
+ case "URL Path":
+ ruleObj = &UrlPathRule{}
case "IP":
ruleObj = &IpRule{}
case "WAF":
diff --git a/rule/rule_url_path.go b/rule/rule_url_path.go
new file mode 100644
index 0000000..93ef412
--- /dev/null
+++ b/rule/rule_url_path.go
@@ -0,0 +1,62 @@
+// Copyright 2024 The casbin Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rule
+
+import (
+ "fmt"
+ "net/http"
+ "regexp"
+ "strings"
+
+ "github.com/casbin/caswaf/object"
+)
+
+type UrlPathRule struct{}
+
+func (r *UrlPathRule) checkRule(expressions []*object.Expression, req
*http.Request) (*RuleResult, error) {
+ path := req.URL.Path
+ for _, expression := range expressions {
+ pattern := expression.Value
+ reason := fmt.Sprintf("expression matched: \"%s %s %s\"", path,
expression.Operator, expression.Value)
+ switch expression.Operator {
+ case "contains":
+ if strings.Contains(path, pattern) {
+ return &RuleResult{Reason: reason}, nil
+ }
+ case "does not contain":
+ if !strings.Contains(path, pattern) {
+ return &RuleResult{Reason: reason}, nil
+ }
+ case "equals":
+ if path == pattern {
+ return &RuleResult{Reason: reason}, nil
+ }
+ case "does not equal":
+ if strings.Compare(path, pattern) != 0 {
+ return &RuleResult{Reason: reason}, nil
+ }
+ case "match":
+ isHit, err := regexp.MatchString(pattern, path)
+ if err != nil {
+ return nil, err
+ }
+ if isHit {
+ return &RuleResult{Reason: reason}, nil
+ }
+ }
+ }
+
+ return nil, nil
+}
diff --git a/web/src/RuleEditPage.js b/web/src/RuleEditPage.js
index 57c7b60..65b1e47 100644
--- a/web/src/RuleEditPage.js
+++ b/web/src/RuleEditPage.js
@@ -99,6 +99,7 @@ class RuleEditPage extends React.Component {
{value: "WAF", text: "WAF"},
{value: "IP", text: "IP"},
{value: "User-Agent", text: "User-Agent"},
+ {value: "URL Path", text: "URL Path"},
{value: "IP Rate Limiting", text: i18next.t("rule:IP Rate
Limiting")},
{value: "Compound", text: i18next.t("rule:Compound")},
].map((item, index) => <Option key={index}
value={item.value}>{item.text}</Option>)
@@ -144,6 +145,18 @@ class RuleEditPage extends React.Component {
/>
) : null
}
+ {
+ this.state.rule.type === "URL Path" ? (
+ <UaRuleTable
+ kind="urlPath"
+ title={"URL Paths"}
+ table={this.state.rule.expressions}
+ ruleName={this.state.rule.name}
+ account={this.props.account}
+ onUpdateTable={(value) =>
{this.updateRuleField("expressions", value);}}
+ />
+ ) : null
+ }
{
this.state.rule.type === "IP Rate Limiting" ? (
<IpRateRuleTable
diff --git a/web/src/components/UaRuleTable.js
b/web/src/components/UaRuleTable.js
index 3d4e92d..c5fe6ef 100644
--- a/web/src/components/UaRuleTable.js
+++ b/web/src/components/UaRuleTable.js
@@ -25,19 +25,31 @@ class UaRuleTable extends React.Component {
super(props);
this.state = {
classes: props,
- defaultRules: [
- {
- name: "Current User-Agent",
- operator: "equals",
- value: window.navigator.userAgent,
- },
- ],
};
if (this.props.table.length === 0) {
this.restore();
}
}
+ getDefaultRules() {
+ if (this.props.kind === "urlPath") {
+ return [
+ {
+ name: "Example",
+ operator: "contains",
+ value: "/.git/config",
+ },
+ ];
+ }
+ return [
+ {
+ name: "Current User-Agent",
+ operator: "equals",
+ value: window.navigator.userAgent,
+ },
+ ];
+ }
+
updateTable(table) {
this.props.onUpdateTable(table);
}
@@ -48,7 +60,12 @@ class UaRuleTable extends React.Component {
}
addRow(table) {
- const row = {name: `New UA Rule - ${table.length}`, operator: "equals",
value: ""};
+ const isPath = this.props.kind === "urlPath";
+ const row = {
+ name: isPath ? `New URL Path Rule - ${table.length}` : `New UA Rule -
${table.length}`,
+ operator: isPath ? "contains" : "equals",
+ value: "",
+ };
if (table === undefined) {
table = [];
}
@@ -73,7 +90,7 @@ class UaRuleTable extends React.Component {
}
restore() {
- this.updateTable(this.state.defaultRules);
+ this.updateTable(this.getDefaultRules());
}
renderTable(table) {
@@ -169,4 +186,8 @@ class UaRuleTable extends React.Component {
}
}
+UaRuleTable.defaultProps = {
+ kind: "userAgent",
+};
+
export default UaRuleTable;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]