Coverage Report

Created: 2026-01-21 08:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/src/permission/permission.cc
Line
Count
Source
1
#include "permission.h"
2
#include "base_object-inl.h"
3
#include "env-inl.h"
4
#include "memory_tracker-inl.h"
5
#include "node.h"
6
#include "node_errors.h"
7
#include "node_external_reference.h"
8
#include "node_file.h"
9
10
#include "v8.h"
11
12
#include <memory>
13
#include <string>
14
#include <vector>
15
16
namespace node {
17
18
using v8::Context;
19
using v8::FunctionCallbackInfo;
20
using v8::IntegrityLevel;
21
using v8::Local;
22
using v8::MaybeLocal;
23
using v8::Object;
24
using v8::Value;
25
26
namespace permission {
27
28
namespace {
29
30
// permission.has('fs.in', '/tmp/')
31
// permission.has('fs.in')
32
0
static void Has(const FunctionCallbackInfo<Value>& args) {
33
0
  Environment* env = Environment::GetCurrent(args);
34
0
  CHECK(args[0]->IsString());
35
36
0
  const std::string deny_scope = Utf8Value(env->isolate(), args[0]).ToString();
37
0
  PermissionScope scope = Permission::StringToPermission(deny_scope);
38
0
  if (scope == PermissionScope::kPermissionsRoot) {
39
0
    return args.GetReturnValue().Set(false);
40
0
  }
41
42
0
  if (args.Length() > 1 && !args[1]->IsUndefined()) {
43
0
    Utf8Value utf8_arg(env->isolate(), args[1]);
44
0
    if (utf8_arg.length() == 0) {
45
0
      args.GetReturnValue().Set(false);
46
0
      return;
47
0
    }
48
0
    return args.GetReturnValue().Set(
49
0
        env->permission()->is_granted(env, scope, utf8_arg.ToStringView()));
50
0
  }
51
52
0
  return args.GetReturnValue().Set(env->permission()->is_granted(env, scope));
53
0
}
54
55
}  // namespace
56
57
#define V(Name, label, _, __)                                                  \
58
0
  if (perm == PermissionScope::k##Name) return #Name;
59
0
const char* Permission::PermissionToString(const PermissionScope perm) {
60
0
  PERMISSIONS(V)
61
0
  return nullptr;
62
0
}
63
#undef V
64
65
#define V(Name, label, _, __)                                                  \
66
0
  if (perm == label) return PermissionScope::k##Name;
67
0
PermissionScope Permission::StringToPermission(const std::string& perm) {
68
0
  PERMISSIONS(V)
69
0
  return PermissionScope::kPermissionsRoot;
70
0
}
71
#undef V
72
73
35
Permission::Permission() : enabled_(false) {
74
35
  std::shared_ptr<PermissionBase> fs = std::make_shared<FSPermission>();
75
35
  std::shared_ptr<PermissionBase> child_p =
76
35
      std::make_shared<ChildProcessPermission>();
77
35
  std::shared_ptr<PermissionBase> worker_t =
78
35
      std::make_shared<WorkerPermission>();
79
35
  std::shared_ptr<PermissionBase> inspector =
80
35
      std::make_shared<InspectorPermission>();
81
35
  std::shared_ptr<PermissionBase> wasi = std::make_shared<WASIPermission>();
82
35
  std::shared_ptr<PermissionBase> net = std::make_shared<NetPermission>();
83
35
  std::shared_ptr<PermissionBase> addon = std::make_shared<AddonPermission>();
84
35
#define V(Name, _, __, ___)                                                    \
85
105
  nodes_.insert(std::make_pair(PermissionScope::k##Name, fs));
86
105
  FILESYSTEM_PERMISSIONS(V)
87
35
#undef V
88
35
#define V(Name, _, __, ___)                                                    \
89
35
  nodes_.insert(std::make_pair(PermissionScope::k##Name, child_p));
90
35
  CHILD_PROCESS_PERMISSIONS(V)
91
35
#undef V
92
35
#define V(Name, _, __, ___)                                                    \
93
35
  nodes_.insert(std::make_pair(PermissionScope::k##Name, worker_t));
94
35
  WORKER_THREADS_PERMISSIONS(V)
95
35
#undef V
96
35
#define V(Name, _, __, ___)                                                    \
97
35
  nodes_.insert(std::make_pair(PermissionScope::k##Name, inspector));
98
35
  INSPECTOR_PERMISSIONS(V)
99
35
#undef V
100
35
#define V(Name, _, __, ___)                                                    \
101
35
  nodes_.insert(std::make_pair(PermissionScope::k##Name, wasi));
102
35
  WASI_PERMISSIONS(V)
103
35
#undef V
104
35
#define V(Name, _, __, ___)                                                    \
105
35
  nodes_.insert(std::make_pair(PermissionScope::k##Name, net));
106
35
  NET_PERMISSIONS(V)
107
35
#undef V
108
35
#define V(Name, _, __, ___)                                                    \
109
35
  nodes_.insert(std::make_pair(PermissionScope::k##Name, addon));
110
35
  ADDON_PERMISSIONS(V)
111
35
#undef V
112
35
}
113
114
0
const char* GetErrorFlagSuggestion(node::permission::PermissionScope perm) {
115
0
  switch (perm) {
116
0
#define V(Name, _, __, Flag)                                                   \
117
0
  case node::permission::PermissionScope::k##Name:                             \
118
0
    return Flag[0] != '\0' ? "Use " Flag " to manage permissions." : "";
119
0
    PERMISSIONS(V)
120
0
#undef V
121
0
    default:
122
0
      return "";
123
0
  }
124
0
}
125
126
MaybeLocal<Value> CreateAccessDeniedError(Environment* env,
127
                                          PermissionScope perm,
128
0
                                          const std::string_view& res) {
129
0
  const char* suggestion = GetErrorFlagSuggestion(perm);
130
0
  Local<Object> err = ERR_ACCESS_DENIED(
131
0
      env->isolate(), "Access to this API has been restricted. %s", suggestion);
132
133
0
  Local<Value> perm_string;
134
0
  Local<Value> resource_string;
135
0
  std::string_view perm_str = Permission::PermissionToString(perm);
136
0
  if (!ToV8Value(env->context(), perm_str, env->isolate())
137
0
           .ToLocal(&perm_string) ||
138
0
      !ToV8Value(env->context(), res, env->isolate())
139
0
           .ToLocal(&resource_string) ||
140
0
      err->Set(env->context(), env->permission_string(), perm_string)
141
0
          .IsNothing() ||
142
0
      err->Set(env->context(), env->resource_string(), resource_string)
143
0
          .IsNothing()) {
144
0
    return MaybeLocal<Value>();
145
0
  }
146
0
  return err;
147
0
}
148
149
void Permission::ThrowAccessDenied(Environment* env,
150
                                   PermissionScope perm,
151
0
                                   const std::string_view& res) {
152
0
  Local<Value> err;
153
0
  if (CreateAccessDeniedError(env, perm, res).ToLocal(&err)) {
154
0
    env->isolate()->ThrowException(err);
155
0
  }
156
  // If ToLocal returned false, then v8 will have scheduled a
157
  // superseding error to be thrown.
158
0
}
159
160
void Permission::AsyncThrowAccessDenied(Environment* env,
161
                                        fs::FSReqBase* req_wrap,
162
                                        PermissionScope perm,
163
0
                                        const std::string_view& res) {
164
0
  Local<Value> err;
165
0
  if (CreateAccessDeniedError(env, perm, res).ToLocal(&err)) {
166
0
    return req_wrap->Reject(err);
167
0
  }
168
  // If ToLocal returned false, then v8 will have scheduled a
169
  // superseding error to be thrown.
170
0
}
171
172
0
void Permission::EnablePermissions() {
173
0
  if (!enabled_) {
174
0
    enabled_ = true;
175
0
  }
176
0
}
177
178
void Permission::Apply(Environment* env,
179
                       const std::vector<std::string>& allow,
180
0
                       PermissionScope scope) {
181
0
  auto permission = nodes_.find(scope);
182
0
  if (permission != nodes_.end()) {
183
0
    permission->second->Apply(env, allow, scope);
184
0
  }
185
0
}
186
187
void Initialize(Local<Object> target,
188
                Local<Value> unused,
189
                Local<Context> context,
190
35
                void* priv) {
191
35
  SetMethodNoSideEffect(context, target, "has", Has);
192
193
35
  target->SetIntegrityLevel(context, IntegrityLevel::kFrozen).FromJust();
194
35
}
195
196
0
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
197
0
  registry->Register(Has);
198
0
}
199
200
}  // namespace permission
201
}  // namespace node
202
203
NODE_BINDING_CONTEXT_AWARE_INTERNAL(permission, node::permission::Initialize)
204
NODE_BINDING_EXTERNAL_REFERENCE(permission,
205
                                node::permission::RegisterExternalReferences)