Skip to content

Commit bb228e5

Browse files
authored
fix:add KeyMatch4() for built-in functions (#211)
1 parent 7051507 commit bb228e5

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

casbin/util/built_in_functions.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef BUILT_IN_FUNCTIONS_CPP
2020
#define BUILT_IN_FUNCTIONS_CPP
2121

22+
#include <map>
2223
#include <regex>
2324

2425
#include "casbin/exception/illegal_argument_exception.h"
@@ -139,6 +140,64 @@ bool KeyMatch3(const std::string& key1, const std::string& key2) {
139140
return res;
140141
}
141142

143+
// KeyMatch4 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
144+
// Besides what KeyMatch3 does, KeyMatch4 can also match repeated patterns:
145+
// "/parent/123/child/123" matches "/parent/{id}/child/{id}"
146+
// "/parent/123/child/456" does not match "/parent/{id}/child/{id}"
147+
// But KeyMatch3 will match both.
148+
bool KeyMatch4(const std::string& key1, const std::string& key2) {
149+
std::vector<std::string> key1_arr = Split(key1, "/");
150+
std::vector<std::string> key2_arr = Split(key2, "/");
151+
std::map<std::string, std::string> tokens_matches;
152+
153+
bool res = true;
154+
for (int i = 0; i < key2_arr.size(); i++) {
155+
if (i >= key1_arr.size()) {
156+
res = false;
157+
break;
158+
}
159+
if (key1_arr[i] != key2_arr[i]) {
160+
size_t index1 = key2_arr[i].find("*");
161+
size_t index2 = key2_arr[i].find("{");
162+
size_t index3 = key2_arr[i].find("}");
163+
std::string token = key2_arr[i].substr(1, key2_arr[i].length() - 2);
164+
if (index1 != std::string::npos) {
165+
if (index1 == 0) {
166+
res = true;
167+
break;
168+
} else if (key1_arr[i].compare(key2_arr[i].substr(0, index1))) {
169+
res = false;
170+
break;
171+
} else
172+
continue;
173+
}
174+
if (index2 == 0 && index3 > 0 && index3 != std::string::npos) {
175+
if (key1_arr[i] == "" || !token.compare("")) {
176+
res = false;
177+
break;
178+
}
179+
if (tokens_matches.find(token) == tokens_matches.end()) {
180+
tokens_matches.insert(std::pair<std::string, std::string>(token, key1_arr[i]));
181+
continue;
182+
} else if (tokens_matches.at(token).compare(key1_arr[i])) {
183+
res = false;
184+
break;
185+
} else
186+
continue;
187+
}
188+
res = false;
189+
break;
190+
} else
191+
continue;
192+
}
193+
194+
if (key2_arr.size() < key1_arr.size())
195+
if (key2_arr[key2_arr.size() - 1] != "*")
196+
res = false;
197+
198+
return res;
199+
}
200+
142201
// RegexMatch determines whether key1 matches the pattern of key2 in regular expression.
143202
bool RegexMatch(const std::string& key1, const std::string& key2) {
144203
std::regex regex_s(key2);

include/casbin/util/built_in_functions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ bool KeyMatch2(const std::string& key1, const std::string& key2);
3131
// For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}"
3232
bool KeyMatch3(const std::string& key1, const std::string& key2);
3333

34+
// KeyMatch4 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
35+
// Besides what KeyMatch3 does, KeyMatch4 can also match repeated patterns:
36+
// "/parent/123/child/123" matches "/parent/{id}/child/{id}"
37+
// "/parent/123/child/456" does not match "/parent/{id}/child/{id}"
38+
// But KeyMatch3 will match both.
39+
bool KeyMatch4(const std::string& key1, const std::string& key2);
40+
3441
// RegexMatch determines whether key1 matches the pattern of key2 in regular expression.
3542
bool RegexMatch(const std::string& key1, const std::string& key2);
3643

0 commit comments

Comments
 (0)