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