summaryrefslogtreecommitdiff
path: root/src/permission/fs_permission.h
blob: 93c427276139fd304eb8c5a866a2212171847ca0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#ifndef SRC_PERMISSION_FS_PERMISSION_H_
#define SRC_PERMISSION_FS_PERMISSION_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "v8.h"

#include <unordered_map>
#include <vector>
#include "permission/permission_base.h"
#include "util.h"

namespace node {

namespace permission {

class FSPermission final : public PermissionBase {
 public:
  void Apply(const std::string& deny, PermissionScope scope) override;
  bool is_granted(PermissionScope perm, const std::string_view& param) override;

  // For debugging purposes, use the gist function to print the whole tree
  // https://gist.github.com/RafaelGSS/5b4f09c559a54f53f9b7c8c030744d19
  struct RadixTree {
    struct Node {
      std::string prefix;
      std::unordered_map<char, Node*> children;
      Node* wildcard_child;

      explicit Node(const std::string& pre)
          : prefix(pre), wildcard_child(nullptr) {}

      Node() : wildcard_child(nullptr) {}

      Node* CreateChild(std::string prefix) {
        char label = prefix[0];

        Node* child = children[label];
        if (child == nullptr) {
          children[label] = new Node(prefix);
          return children[label];
        }

        // swap prefix
        unsigned int i = 0;
        unsigned int prefix_len = prefix.length();
        for (; i < child->prefix.length(); ++i) {
          if (i > prefix_len || prefix[i] != child->prefix[i]) {
            std::string parent_prefix = child->prefix.substr(0, i);
            std::string child_prefix = child->prefix.substr(i);

            child->prefix = child_prefix;
            Node* split_child = new Node(parent_prefix);
            split_child->children[child_prefix[0]] = child;
            children[parent_prefix[0]] = split_child;

            return split_child->CreateChild(prefix.substr(i));
          }
        }
        return child->CreateChild(prefix.substr(i));
      }

      Node* CreateWildcardChild() {
        if (wildcard_child != nullptr) {
          return wildcard_child;
        }
        wildcard_child = new Node();
        return wildcard_child;
      }

      Node* NextNode(const std::string& path, unsigned int idx) {
        if (idx >= path.length()) {
          return nullptr;
        }

        auto it = children.find(path[idx]);
        if (it == children.end()) {
          return nullptr;
        }
        auto child = it->second;
        // match prefix
        unsigned int prefix_len = child->prefix.length();
        for (unsigned int i = 0; i < path.length(); ++i) {
          if (i >= prefix_len || child->prefix[i] == '*') {
            return child;
          }

          // Handle optional trailing
          // path = /home/subdirectory
          // child = subdirectory/*
          if (idx >= path.length() &&
              child->prefix[i] == node::kPathSeparator) {
            continue;
          }

          if (path[idx++] != child->prefix[i]) {
            return nullptr;
          }
        }
        return child;
      }

      // A node can be a *end* node and have children
      // E.g: */slower*, */slown* are inserted:
      // /slow
      // ---> er
      // ---> n
      // If */slow* is inserted right after, it will create an
      // empty node
      // /slow
      // ---> '\000' ASCII (0) || \0
      // ---> er
      // ---> n
      bool IsEndNode() {
        if (children.size() == 0) {
          return true;
        }
        return children['\0'] != nullptr;
      }
    };

    RadixTree();
    ~RadixTree();
    void Insert(const std::string& s);
    bool Lookup(const std::string_view& s) { return Lookup(s, false); }
    bool Lookup(const std::string_view& s, bool when_empty_return);

   private:
    Node* root_node_;
  };

 private:
  void GrantAccess(PermissionScope scope, std::string param);
  void RestrictAccess(PermissionScope scope,
                      const std::vector<std::string>& params);
  // fs granted on startup
  RadixTree granted_in_fs_;
  RadixTree granted_out_fs_;

  bool deny_all_in_ = true;
  bool deny_all_out_ = true;

  bool allow_all_in_ = false;
  bool allow_all_out_ = false;
};

}  // namespace permission

}  // namespace node

#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif  // SRC_PERMISSION_FS_PERMISSION_H_