Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 933673d

Browse filesBrowse files
anonrigMoLow
authored andcommitted
src: avoid copying string in fs_permission
PR-URL: #47746 Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Deokjin Kim <deokjin81.kim@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com>
1 parent 0927c67 commit 933673d
Copy full SHA for 933673d

File tree

Expand file treeCollapse file tree

2 files changed

+332
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

2 files changed

+332
-0
lines changed
Open diff view settings
Collapse file

‎src/permission/fs_permission.cc‎

Copy file name to clipboard
+180Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#include "fs_permission.h"
2+
#include "base_object-inl.h"
3+
#include "util.h"
4+
#include "v8.h"
5+
6+
#include <fcntl.h>
7+
#include <limits.h>
8+
#include <stdlib.h>
9+
#include <algorithm>
10+
#include <filesystem>
11+
#include <string>
12+
#include <vector>
13+
14+
namespace {
15+
16+
std::string WildcardIfDir(const std::string& res) noexcept {
17+
uv_fs_t req;
18+
int rc = uv_fs_stat(nullptr, &req, res.c_str(), nullptr);
19+
if (rc == 0) {
20+
const uv_stat_t* const s = static_cast<const uv_stat_t*>(req.ptr);
21+
if (s->st_mode & S_IFDIR) {
22+
// add wildcard when directory
23+
if (res.back() == node::kPathSeparator) {
24+
return res + "*";
25+
}
26+
return res + node::kPathSeparator + "*";
27+
}
28+
}
29+
uv_fs_req_cleanup(&req);
30+
return res;
31+
}
32+
33+
void FreeRecursivelyNode(
34+
node::permission::FSPermission::RadixTree::Node* node) {
35+
if (node == nullptr) {
36+
return;
37+
}
38+
39+
if (node->children.size()) {
40+
for (auto& c : node->children) {
41+
FreeRecursivelyNode(c.second);
42+
}
43+
}
44+
45+
if (node->wildcard_child != nullptr) {
46+
delete node->wildcard_child;
47+
}
48+
delete node;
49+
}
50+
51+
bool is_tree_granted(node::permission::FSPermission::RadixTree* granted_tree,
52+
const std::string_view& param) {
53+
#ifdef _WIN32
54+
// is UNC file path
55+
if (param.rfind("\\\\", 0) == 0) {
56+
// return lookup with normalized param
57+
int starting_pos = 4; // "\\?\"
58+
if (param.rfind("\\\\?\\UNC\\") == 0) {
59+
starting_pos += 4; // "UNC\"
60+
}
61+
auto normalized = param.substr(starting_pos);
62+
return granted_tree->Lookup(normalized, true);
63+
}
64+
#endif
65+
return granted_tree->Lookup(param, true);
66+
}
67+
68+
} // namespace
69+
70+
namespace node {
71+
72+
namespace permission {
73+
74+
// allow = '*'
75+
// allow = '/tmp/,/home/example.js'
76+
void FSPermission::Apply(const std::string& allow, PermissionScope scope) {
77+
for (const auto& res : SplitString(allow, ',')) {
78+
if (res == "*") {
79+
if (scope == PermissionScope::kFileSystemRead) {
80+
deny_all_in_ = false;
81+
allow_all_in_ = true;
82+
} else {
83+
deny_all_out_ = false;
84+
allow_all_out_ = true;
85+
}
86+
return;
87+
}
88+
GrantAccess(scope, res);
89+
}
90+
}
91+
92+
void FSPermission::GrantAccess(PermissionScope perm, const std::string& res) {
93+
const std::string path = WildcardIfDir(res);
94+
if (perm == PermissionScope::kFileSystemRead) {
95+
granted_in_fs_.Insert(path);
96+
deny_all_in_ = false;
97+
} else if (perm == PermissionScope::kFileSystemWrite) {
98+
granted_out_fs_.Insert(path);
99+
deny_all_out_ = false;
100+
}
101+
}
102+
103+
bool FSPermission::is_granted(PermissionScope perm,
104+
const std::string_view& param = "") {
105+
switch (perm) {
106+
case PermissionScope::kFileSystem:
107+
return allow_all_in_ && allow_all_out_;
108+
case PermissionScope::kFileSystemRead:
109+
return !deny_all_in_ &&
110+
((param.empty() && allow_all_in_) || allow_all_in_ ||
111+
is_tree_granted(&granted_in_fs_, param));
112+
case PermissionScope::kFileSystemWrite:
113+
return !deny_all_out_ &&
114+
((param.empty() && allow_all_out_) || allow_all_out_ ||
115+
is_tree_granted(&granted_out_fs_, param));
116+
default:
117+
return false;
118+
}
119+
}
120+
121+
FSPermission::RadixTree::RadixTree() : root_node_(new Node("")) {}
122+
123+
FSPermission::RadixTree::~RadixTree() {
124+
FreeRecursivelyNode(root_node_);
125+
}
126+
127+
bool FSPermission::RadixTree::Lookup(const std::string_view& s,
128+
bool when_empty_return = false) {
129+
FSPermission::RadixTree::Node* current_node = root_node_;
130+
if (current_node->children.size() == 0) {
131+
return when_empty_return;
132+
}
133+
134+
unsigned int parent_node_prefix_len = current_node->prefix.length();
135+
const std::string path(s);
136+
auto path_len = path.length();
137+
138+
while (true) {
139+
if (parent_node_prefix_len == path_len && current_node->IsEndNode()) {
140+
return true;
141+
}
142+
143+
auto node = current_node->NextNode(path, parent_node_prefix_len);
144+
if (node == nullptr) {
145+
return false;
146+
}
147+
148+
current_node = node;
149+
parent_node_prefix_len += current_node->prefix.length();
150+
if (current_node->wildcard_child != nullptr &&
151+
path_len >= (parent_node_prefix_len - 2 /* slash* */)) {
152+
return true;
153+
}
154+
}
155+
}
156+
157+
void FSPermission::RadixTree::Insert(const std::string& path) {
158+
FSPermission::RadixTree::Node* current_node = root_node_;
159+
160+
unsigned int parent_node_prefix_len = current_node->prefix.length();
161+
int path_len = path.length();
162+
163+
for (int i = 1; i <= path_len; ++i) {
164+
bool is_wildcard_node = path[i - 1] == '*';
165+
bool is_last_char = i == path_len;
166+
167+
if (is_wildcard_node || is_last_char) {
168+
std::string node_path = path.substr(parent_node_prefix_len, i);
169+
current_node = current_node->CreateChild(node_path);
170+
}
171+
172+
if (is_wildcard_node) {
173+
current_node = current_node->CreateWildcardChild();
174+
parent_node_prefix_len = i;
175+
}
176+
}
177+
}
178+
179+
} // namespace permission
180+
} // namespace node
Collapse file

‎src/permission/fs_permission.h‎

Copy file name to clipboard
+152Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
#ifndef SRC_PERMISSION_FS_PERMISSION_H_
2+
#define SRC_PERMISSION_FS_PERMISSION_H_
3+
4+
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
5+
6+
#include "v8.h"
7+
8+
#include <unordered_map>
9+
#include <vector>
10+
#include "permission/permission_base.h"
11+
#include "util.h"
12+
13+
namespace node {
14+
15+
namespace permission {
16+
17+
class FSPermission final : public PermissionBase {
18+
public:
19+
void Apply(const std::string& deny, PermissionScope scope) override;
20+
bool is_granted(PermissionScope perm, const std::string_view& param) override;
21+
22+
// For debugging purposes, use the gist function to print the whole tree
23+
// https://gist.github.com/RafaelGSS/5b4f09c559a54f53f9b7c8c030744d19
24+
struct RadixTree {
25+
struct Node {
26+
std::string prefix;
27+
std::unordered_map<char, Node*> children;
28+
Node* wildcard_child;
29+
30+
explicit Node(const std::string& pre)
31+
: prefix(pre), wildcard_child(nullptr) {}
32+
33+
Node() : wildcard_child(nullptr) {}
34+
35+
Node* CreateChild(std::string prefix) {
36+
char label = prefix[0];
37+
38+
Node* child = children[label];
39+
if (child == nullptr) {
40+
children[label] = new Node(prefix);
41+
return children[label];
42+
}
43+
44+
// swap prefix
45+
unsigned int i = 0;
46+
unsigned int prefix_len = prefix.length();
47+
for (; i < child->prefix.length(); ++i) {
48+
if (i > prefix_len || prefix[i] != child->prefix[i]) {
49+
std::string parent_prefix = child->prefix.substr(0, i);
50+
std::string child_prefix = child->prefix.substr(i);
51+
52+
child->prefix = child_prefix;
53+
Node* split_child = new Node(parent_prefix);
54+
split_child->children[child_prefix[0]] = child;
55+
children[parent_prefix[0]] = split_child;
56+
57+
return split_child->CreateChild(prefix.substr(i));
58+
}
59+
}
60+
return child->CreateChild(prefix.substr(i));
61+
}
62+
63+
Node* CreateWildcardChild() {
64+
if (wildcard_child != nullptr) {
65+
return wildcard_child;
66+
}
67+
wildcard_child = new Node();
68+
return wildcard_child;
69+
}
70+
71+
Node* NextNode(const std::string& path, unsigned int idx) {
72+
if (idx >= path.length()) {
73+
return nullptr;
74+
}
75+
76+
auto it = children.find(path[idx]);
77+
if (it == children.end()) {
78+
return nullptr;
79+
}
80+
auto child = it->second;
81+
// match prefix
82+
unsigned int prefix_len = child->prefix.length();
83+
for (unsigned int i = 0; i < path.length(); ++i) {
84+
if (i >= prefix_len || child->prefix[i] == '*') {
85+
return child;
86+
}
87+
88+
// Handle optional trailing
89+
// path = /home/subdirectory
90+
// child = subdirectory/*
91+
if (idx >= path.length() &&
92+
child->prefix[i] == node::kPathSeparator) {
93+
continue;
94+
}
95+
96+
if (path[idx++] != child->prefix[i]) {
97+
return nullptr;
98+
}
99+
}
100+
return child;
101+
}
102+
103+
// A node can be a *end* node and have children
104+
// E.g: */slower*, */slown* are inserted:
105+
// /slow
106+
// ---> er
107+
// ---> n
108+
// If */slow* is inserted right after, it will create an
109+
// empty node
110+
// /slow
111+
// ---> '\000' ASCII (0) || \0
112+
// ---> er
113+
// ---> n
114+
bool IsEndNode() {
115+
if (children.size() == 0) {
116+
return true;
117+
}
118+
return children['\0'] != nullptr;
119+
}
120+
};
121+
122+
RadixTree();
123+
~RadixTree();
124+
void Insert(const std::string& s);
125+
bool Lookup(const std::string_view& s) { return Lookup(s, false); }
126+
bool Lookup(const std::string_view& s, bool when_empty_return);
127+
128+
private:
129+
Node* root_node_;
130+
};
131+
132+
private:
133+
void GrantAccess(PermissionScope scope, const std::string& param);
134+
void RestrictAccess(PermissionScope scope,
135+
const std::vector<std::string>& params);
136+
// fs granted on startup
137+
RadixTree granted_in_fs_;
138+
RadixTree granted_out_fs_;
139+
140+
bool deny_all_in_ = true;
141+
bool deny_all_out_ = true;
142+
143+
bool allow_all_in_ = false;
144+
bool allow_all_out_ = false;
145+
};
146+
147+
} // namespace permission
148+
149+
} // namespace node
150+
151+
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
152+
#endif // SRC_PERMISSION_FS_PERMISSION_H_

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.