Coverage Report

Created: 2025-07-04 09:33

/src/node/src/permission/fs_permission.h
Line
Count
Source (jump to first uncovered line)
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 "permission/permission_base.h"
10
#include "util.h"
11
12
namespace node {
13
14
namespace permission {
15
16
class FSPermission final : public PermissionBase {
17
 public:
18
  void Apply(Environment* env,
19
             const std::vector<std::string>& allow,
20
             PermissionScope scope) override;
21
  bool is_granted(PermissionScope perm,
22
                  const std::string_view& param) const override;
23
24
  struct RadixTree {
25
    struct Node {
26
      std::string prefix;
27
      std::unordered_map<char, Node*> children;
28
      Node* wildcard_child;
29
      bool is_leaf;
30
31
      explicit Node(const std::string& pre)
32
269k
          : prefix(pre), wildcard_child(nullptr), is_leaf(false) {}
33
34
0
      Node() : wildcard_child(nullptr), is_leaf(false) {}
35
36
0
      Node* CreateChild(const std::string& path_prefix) {
37
0
        if (path_prefix.empty() && !is_leaf) {
38
0
          is_leaf = true;
39
0
          return this;
40
0
        }
41
42
0
        CHECK(!path_prefix.empty());
43
0
        char label = path_prefix[0];
44
45
0
        Node* child = children[label];
46
0
        if (child == nullptr) {
47
0
          children[label] = new Node(path_prefix);
48
0
          return children[label];
49
0
        }
50
51
        // swap prefix
52
0
        size_t i = 0;
53
0
        size_t prefix_len = path_prefix.length();
54
0
        for (; i < child->prefix.length(); ++i) {
55
0
          if (i > prefix_len || path_prefix[i] != child->prefix[i]) {
56
0
            std::string parent_prefix = child->prefix.substr(0, i);
57
0
            std::string child_prefix = child->prefix.substr(i);
58
59
0
            child->prefix = child_prefix;
60
0
            Node* split_child = new Node(parent_prefix);
61
0
            split_child->children[child_prefix[0]] = child;
62
0
            children[parent_prefix[0]] = split_child;
63
64
0
            return split_child->CreateChild(path_prefix.substr(i));
65
0
          }
66
0
        }
67
0
        child->is_leaf = true;
68
0
        return child->CreateChild(path_prefix.substr(i));
69
0
      }
70
71
0
      Node* CreateWildcardChild() {
72
0
        if (wildcard_child != nullptr) {
73
0
          return wildcard_child;
74
0
        }
75
0
        wildcard_child = new Node();
76
0
        return wildcard_child;
77
0
      }
78
79
0
      Node* NextNode(const std::string& path, size_t idx) const {
80
0
        if (idx >= path.length()) {
81
0
          return nullptr;
82
0
        }
83
84
        // wildcard node takes precedence
85
0
        if (children.size() > 1) {
86
0
          auto it = children.find('*');
87
0
          if (it != children.end()) {
88
0
            return it->second;
89
0
          }
90
0
        }
91
92
0
        auto it = children.find(path[idx]);
93
0
        if (it == children.end()) {
94
0
          return nullptr;
95
0
        }
96
0
        auto child = it->second;
97
        // match prefix
98
0
        size_t prefix_len = child->prefix.length();
99
0
        for (size_t i = 0; i < path.length(); ++i) {
100
0
          if (i >= prefix_len || child->prefix[i] == '*') {
101
0
            return child;
102
0
          }
103
104
          // Handle optional trailing
105
          // path = /home/subdirectory
106
          // child = subdirectory/*
107
0
          if (idx >= path.length() &&
108
0
              child->prefix[i] == node::kPathSeparator) {
109
0
            continue;
110
0
          }
111
112
0
          if (path[idx++] != child->prefix[i]) {
113
0
            return nullptr;
114
0
          }
115
0
        }
116
0
        return child;
117
0
      }
118
119
      // A node can be a *end* node and have children
120
      // E.g: */slower*, */slown* are inserted:
121
      // /slow
122
      // ---> er
123
      // ---> n
124
      // If */slow* is inserted right after, it will create an
125
      // empty node
126
      // /slow
127
      // ---> '\000' ASCII (0) || \0
128
      // ---> er
129
      // ---> n
130
0
      bool IsEndNode() const {
131
0
        if (children.size() == 0) {
132
0
          return true;
133
0
        }
134
0
        return is_leaf;
135
0
      }
136
    };
137
138
    RadixTree();
139
    ~RadixTree();
140
    void Insert(const std::string& s);
141
0
    bool Lookup(const std::string_view& s) const { return Lookup(s, false); }
142
    bool Lookup(const std::string_view& s, bool when_empty_return) const;
143
144
   private:
145
    Node* root_node_;
146
  };
147
148
 private:
149
  void GrantAccess(PermissionScope scope, const std::string& param);
150
  // fs granted on startup
151
  RadixTree granted_in_fs_;
152
  RadixTree granted_out_fs_;
153
154
  bool deny_all_in_ = true;
155
  bool deny_all_out_ = true;
156
157
  bool allow_all_in_ = false;
158
  bool allow_all_out_ = false;
159
};
160
161
}  // namespace permission
162
163
}  // namespace node
164
165
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
166
#endif  // SRC_PERMISSION_FS_PERMISSION_H_