mirror of
https://github.com/nodejs/node.git
synced 2025-12-28 07:50:41 +00:00
lib,src,permission: port path.resolve to C++
Co-Authored-By: Carlos Espa <cespatorres@gmail.com> PR-URL: https://github.com/nodejs/node/pull/50758 Refs: https://github.com/nodejs/security-wg/issues/898 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Claudio Wunder <cwunder@gnome.org>
This commit is contained in:
parent
461ffcadff
commit
338a5be272
2
node.gyp
2
node.gyp
@ -143,6 +143,7 @@
|
||||
'src/node_watchdog.cc',
|
||||
'src/node_worker.cc',
|
||||
'src/node_zlib.cc',
|
||||
'src/path.cc',
|
||||
'src/permission/child_process_permission.cc',
|
||||
'src/permission/fs_permission.cc',
|
||||
'src/permission/inspector_permission.cc',
|
||||
@ -264,6 +265,7 @@
|
||||
'src/node_wasi.h',
|
||||
'src/node_watchdog.h',
|
||||
'src/node_worker.h',
|
||||
'src/path.h',
|
||||
'src/permission/child_process_permission.h',
|
||||
'src/permission/fs_permission.h',
|
||||
'src/permission/inspector_permission.h',
|
||||
|
||||
14
src/env.cc
14
src/env.cc
@ -898,21 +898,25 @@ Environment::Environment(IsolateData* isolate_data,
|
||||
options_->allow_native_addons = false;
|
||||
}
|
||||
flags_ = flags_ | EnvironmentFlags::kNoCreateInspector;
|
||||
permission()->Apply({"*"}, permission::PermissionScope::kInspector);
|
||||
permission()->Apply(this, {"*"}, permission::PermissionScope::kInspector);
|
||||
if (!options_->allow_child_process) {
|
||||
permission()->Apply({"*"}, permission::PermissionScope::kChildProcess);
|
||||
permission()->Apply(
|
||||
this, {"*"}, permission::PermissionScope::kChildProcess);
|
||||
}
|
||||
if (!options_->allow_worker_threads) {
|
||||
permission()->Apply({"*"}, permission::PermissionScope::kWorkerThreads);
|
||||
permission()->Apply(
|
||||
this, {"*"}, permission::PermissionScope::kWorkerThreads);
|
||||
}
|
||||
|
||||
if (!options_->allow_fs_read.empty()) {
|
||||
permission()->Apply(options_->allow_fs_read,
|
||||
permission()->Apply(this,
|
||||
options_->allow_fs_read,
|
||||
permission::PermissionScope::kFileSystemRead);
|
||||
}
|
||||
|
||||
if (!options_->allow_fs_write.empty()) {
|
||||
permission()->Apply(options_->allow_fs_write,
|
||||
permission()->Apply(this,
|
||||
options_->allow_fs_write,
|
||||
permission::PermissionScope::kFileSystemWrite);
|
||||
}
|
||||
}
|
||||
|
||||
272
src/path.cc
Normal file
272
src/path.cc
Normal file
@ -0,0 +1,272 @@
|
||||
#include "path.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "env-inl.h"
|
||||
#include "node_internals.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
#ifdef _WIN32
|
||||
bool IsPathSeparator(const char c) noexcept {
|
||||
return c == kPathSeparator || c == '/';
|
||||
}
|
||||
#else // POSIX
|
||||
bool IsPathSeparator(const char c) noexcept {
|
||||
return c == kPathSeparator;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
std::string NormalizeString(const std::string_view path,
|
||||
bool allowAboveRoot,
|
||||
const std::string_view separator) {
|
||||
std::string res;
|
||||
int lastSegmentLength = 0;
|
||||
int lastSlash = -1;
|
||||
int dots = 0;
|
||||
char code;
|
||||
const auto pathLen = path.size();
|
||||
for (uint8_t i = 0; i <= pathLen; ++i) {
|
||||
if (i < pathLen) {
|
||||
code = path[i];
|
||||
} else if (IsPathSeparator(path[i])) {
|
||||
break;
|
||||
} else {
|
||||
code = node::kPathSeparator;
|
||||
}
|
||||
|
||||
if (IsPathSeparator(code)) {
|
||||
if (lastSlash == static_cast<int>(i - 1) || dots == 1) {
|
||||
// NOOP
|
||||
} else if (dots == 2) {
|
||||
int len = res.length();
|
||||
if (len < 2 || lastSegmentLength != 2 || res[len - 1] != '.' ||
|
||||
res[len - 2] != '.') {
|
||||
if (len > 2) {
|
||||
auto lastSlashIndex = res.find_last_of(separator);
|
||||
if (lastSlashIndex == std::string::npos) {
|
||||
res = "";
|
||||
lastSegmentLength = 0;
|
||||
} else {
|
||||
res = res.substr(0, lastSlashIndex);
|
||||
len = res.length();
|
||||
lastSegmentLength = len - 1 - res.find_last_of(separator);
|
||||
}
|
||||
lastSlash = i;
|
||||
dots = 0;
|
||||
continue;
|
||||
} else if (len != 0) {
|
||||
res = "";
|
||||
lastSegmentLength = 0;
|
||||
lastSlash = i;
|
||||
dots = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (allowAboveRoot) {
|
||||
res += res.length() > 0 ? std::string(separator) + ".." : "..";
|
||||
lastSegmentLength = 2;
|
||||
}
|
||||
} else {
|
||||
if (!res.empty()) {
|
||||
res += std::string(separator) +
|
||||
std::string(path.substr(lastSlash + 1, i - (lastSlash + 1)));
|
||||
} else {
|
||||
res = path.substr(lastSlash + 1, i - (lastSlash + 1));
|
||||
}
|
||||
lastSegmentLength = i - lastSlash - 1;
|
||||
}
|
||||
lastSlash = i;
|
||||
dots = 0;
|
||||
} else if (code == '.' && dots != -1) {
|
||||
++dots;
|
||||
} else {
|
||||
dots = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
bool IsWindowsDeviceRoot(const char c) noexcept {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
std::string PathResolve(Environment* env,
|
||||
const std::vector<std::string_view>& paths) {
|
||||
std::string resolvedDevice = "";
|
||||
std::string resolvedTail = "";
|
||||
bool resolvedAbsolute = false;
|
||||
const size_t numArgs = paths.size();
|
||||
auto cwd = env->GetCwd(env->exec_path());
|
||||
|
||||
for (int i = numArgs - 1; i >= -1 && !resolvedAbsolute; i--) {
|
||||
std::string path;
|
||||
if (i >= 0) {
|
||||
path = std::string(paths[i]);
|
||||
} else if (resolvedDevice.empty()) {
|
||||
path = cwd;
|
||||
} else {
|
||||
// Windows has the concept of drive-specific current working
|
||||
// directories. If we've resolved a drive letter but not yet an
|
||||
// absolute path, get cwd for that drive, or the process cwd if
|
||||
// the drive cwd is not available. We're sure the device is not
|
||||
// a UNC path at this points, because UNC paths are always absolute.
|
||||
std::string resolvedDevicePath;
|
||||
const std::string envvar = "=" + resolvedDevice;
|
||||
credentials::SafeGetenv(envvar.c_str(), &resolvedDevicePath);
|
||||
path = resolvedDevicePath.empty() ? cwd : resolvedDevicePath;
|
||||
|
||||
// Verify that a cwd was found and that it actually points
|
||||
// to our drive. If not, default to the drive's root.
|
||||
if (path.empty() ||
|
||||
(ToLower(path.substr(0, 2)) != ToLower(resolvedDevice) &&
|
||||
path[2] == '/')) {
|
||||
path = resolvedDevice + "\\";
|
||||
}
|
||||
}
|
||||
|
||||
const size_t len = path.length();
|
||||
int rootEnd = 0;
|
||||
std::string device = "";
|
||||
bool isAbsolute = false;
|
||||
const char code = path[0];
|
||||
|
||||
// Try to match a root
|
||||
if (len == 1) {
|
||||
if (IsPathSeparator(code)) {
|
||||
// `path` contains just a path separator
|
||||
rootEnd = 1;
|
||||
isAbsolute = true;
|
||||
}
|
||||
} else if (IsPathSeparator(code)) {
|
||||
// Possible UNC root
|
||||
|
||||
// If we started with a separator, we know we at least have an
|
||||
// absolute path of some kind (UNC or otherwise)
|
||||
isAbsolute = true;
|
||||
|
||||
if (IsPathSeparator(path[1])) {
|
||||
// Matched double path separator at beginning
|
||||
size_t j = 2;
|
||||
size_t last = j;
|
||||
// Match 1 or more non-path separators
|
||||
while (j < len && !IsPathSeparator(path[j])) {
|
||||
j++;
|
||||
}
|
||||
if (j < len && j != last) {
|
||||
const std::string firstPart = path.substr(last, j - last);
|
||||
// Matched!
|
||||
last = j;
|
||||
// Match 1 or more path separators
|
||||
while (j < len && IsPathSeparator(path[j])) {
|
||||
j++;
|
||||
}
|
||||
if (j < len && j != last) {
|
||||
// Matched!
|
||||
last = j;
|
||||
// Match 1 or more non-path separators
|
||||
while (j < len && !IsPathSeparator(path[j])) {
|
||||
j++;
|
||||
}
|
||||
if (j == len || j != last) {
|
||||
// We matched a UNC root
|
||||
device = "\\\\" + firstPart + "\\" + path.substr(last, j - last);
|
||||
rootEnd = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (IsWindowsDeviceRoot(code) && path[1] == ':') {
|
||||
// Possible device root
|
||||
device = path.substr(0, 2);
|
||||
rootEnd = 2;
|
||||
if (len > 2 && IsPathSeparator(path[2])) {
|
||||
// Treat separator following drive name as an absolute path
|
||||
// indicator
|
||||
isAbsolute = true;
|
||||
rootEnd = 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device.empty()) {
|
||||
if (!resolvedDevice.empty()) {
|
||||
if (ToLower(device) != ToLower(resolvedDevice)) {
|
||||
// This path points to another device so it is not applicable
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
resolvedDevice = device;
|
||||
}
|
||||
}
|
||||
|
||||
if (resolvedAbsolute) {
|
||||
if (!resolvedDevice.empty()) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
resolvedTail = path.substr(rootEnd) + "\\" + resolvedTail;
|
||||
resolvedAbsolute = isAbsolute;
|
||||
if (isAbsolute && !resolvedDevice.empty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At this point the path should be resolved to a full absolute path,
|
||||
// but handle relative paths to be safe (might happen when process.cwd()
|
||||
// fails)
|
||||
|
||||
// Normalize the tail path
|
||||
resolvedTail = NormalizeString(resolvedTail, !resolvedAbsolute, "\\");
|
||||
|
||||
if (resolvedAbsolute) {
|
||||
return resolvedDevice + "\\" + resolvedTail;
|
||||
}
|
||||
|
||||
if (!resolvedDevice.empty() || !resolvedTail.empty()) {
|
||||
return resolvedDevice + resolvedTail;
|
||||
}
|
||||
|
||||
return ".";
|
||||
}
|
||||
#else // _WIN32
|
||||
std::string PathResolve(Environment* env,
|
||||
const std::vector<std::string_view>& paths) {
|
||||
std::string resolvedPath;
|
||||
bool resolvedAbsolute = false;
|
||||
auto cwd = env->GetCwd(env->exec_path());
|
||||
const size_t numArgs = paths.size();
|
||||
|
||||
for (int i = numArgs - 1; i >= -1 && !resolvedAbsolute; i--) {
|
||||
const std::string& path =
|
||||
(i >= 0) ? std::string(paths[i]) : env->GetCwd(env->exec_path());
|
||||
|
||||
if (!path.empty()) {
|
||||
resolvedPath = std::string(path) + "/" + resolvedPath;
|
||||
|
||||
if (path.front() == '/') {
|
||||
resolvedAbsolute = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize the path
|
||||
auto normalizedPath = NormalizeString(resolvedPath, !resolvedAbsolute, "/");
|
||||
|
||||
if (resolvedAbsolute) {
|
||||
return "/" + normalizedPath;
|
||||
}
|
||||
|
||||
if (normalizedPath.empty()) {
|
||||
return ".";
|
||||
}
|
||||
|
||||
return normalizedPath;
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
} // namespace node
|
||||
25
src/path.h
Normal file
25
src/path.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef SRC_PATH_H_
|
||||
#define SRC_PATH_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace node {
|
||||
|
||||
class Environment;
|
||||
|
||||
bool IsPathSeparator(const char c) noexcept;
|
||||
|
||||
std::string NormalizeString(const std::string_view path,
|
||||
bool allowAboveRoot,
|
||||
const std::string_view separator);
|
||||
|
||||
std::string PathResolve(Environment* env,
|
||||
const std::vector<std::string_view>& args);
|
||||
} // namespace node
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#endif // SRC_PATH_H_
|
||||
@ -9,7 +9,8 @@ namespace permission {
|
||||
|
||||
// Currently, ChildProcess manage a single state
|
||||
// Once denied, it's always denied
|
||||
void ChildProcessPermission::Apply(const std::vector<std::string>& allow,
|
||||
void ChildProcessPermission::Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) {
|
||||
deny_all_ = true;
|
||||
}
|
||||
|
||||
@ -12,7 +12,8 @@ namespace permission {
|
||||
|
||||
class ChildProcessPermission final : public PermissionBase {
|
||||
public:
|
||||
void Apply(const std::vector<std::string>& allow,
|
||||
void Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) override;
|
||||
bool is_granted(PermissionScope perm,
|
||||
const std::string_view& param = "") const override;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#include "fs_permission.h"
|
||||
#include "base_object-inl.h"
|
||||
#include "debug_utils-inl.h"
|
||||
#include "util.h"
|
||||
#include "path.h"
|
||||
#include "v8.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
@ -117,7 +117,8 @@ namespace permission {
|
||||
|
||||
// allow = '*'
|
||||
// allow = '/tmp/,/home/example.js'
|
||||
void FSPermission::Apply(const std::vector<std::string>& allow,
|
||||
void FSPermission::Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) {
|
||||
for (const std::string& res : allow) {
|
||||
if (res == "*") {
|
||||
@ -130,7 +131,7 @@ void FSPermission::Apply(const std::vector<std::string>& allow,
|
||||
}
|
||||
return;
|
||||
}
|
||||
GrantAccess(scope, res);
|
||||
GrantAccess(scope, PathResolve(env, {res}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,8 @@ namespace permission {
|
||||
|
||||
class FSPermission final : public PermissionBase {
|
||||
public:
|
||||
void Apply(const std::vector<std::string>& allow,
|
||||
void Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) override;
|
||||
bool is_granted(PermissionScope perm,
|
||||
const std::string_view& param) const override;
|
||||
|
||||
@ -8,7 +8,8 @@ namespace permission {
|
||||
|
||||
// Currently, Inspector manage a single state
|
||||
// Once denied, it's always denied
|
||||
void InspectorPermission::Apply(const std::vector<std::string>& allow,
|
||||
void InspectorPermission::Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) {
|
||||
deny_all_ = true;
|
||||
}
|
||||
|
||||
@ -12,7 +12,8 @@ namespace permission {
|
||||
|
||||
class InspectorPermission final : public PermissionBase {
|
||||
public:
|
||||
void Apply(const std::vector<std::string>& allow,
|
||||
void Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) override;
|
||||
bool is_granted(PermissionScope perm,
|
||||
const std::string_view& param = "") const override;
|
||||
|
||||
@ -130,11 +130,12 @@ void Permission::EnablePermissions() {
|
||||
}
|
||||
}
|
||||
|
||||
void Permission::Apply(const std::vector<std::string>& allow,
|
||||
void Permission::Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) {
|
||||
auto permission = nodes_.find(scope);
|
||||
if (permission != nodes_.end()) {
|
||||
permission->second->Apply(allow, scope);
|
||||
permission->second->Apply(env, allow, scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,9 @@ class Permission {
|
||||
const std::string_view& res);
|
||||
|
||||
// CLI Call
|
||||
void Apply(const std::vector<std::string>& allow, PermissionScope scope);
|
||||
void Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope);
|
||||
void EnablePermissions();
|
||||
|
||||
private:
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
|
||||
namespace node {
|
||||
|
||||
class Environment;
|
||||
|
||||
namespace permission {
|
||||
|
||||
#define FILESYSTEM_PERMISSIONS(V) \
|
||||
@ -39,7 +41,8 @@ enum class PermissionScope {
|
||||
|
||||
class PermissionBase {
|
||||
public:
|
||||
virtual void Apply(const std::vector<std::string>& allow,
|
||||
virtual void Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) = 0;
|
||||
virtual bool is_granted(PermissionScope perm,
|
||||
const std::string_view& param = "") const = 0;
|
||||
|
||||
@ -9,7 +9,8 @@ namespace permission {
|
||||
|
||||
// Currently, PolicyDenyWorker manage a single state
|
||||
// Once denied, it's always denied
|
||||
void WorkerPermission::Apply(const std::vector<std::string>& allow,
|
||||
void WorkerPermission::Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) {
|
||||
deny_all_ = true;
|
||||
}
|
||||
|
||||
@ -12,7 +12,8 @@ namespace permission {
|
||||
|
||||
class WorkerPermission final : public PermissionBase {
|
||||
public:
|
||||
void Apply(const std::vector<std::string>& allow,
|
||||
void Apply(Environment* env,
|
||||
const std::vector<std::string>& allow,
|
||||
PermissionScope scope) override;
|
||||
bool is_granted(PermissionScope perm,
|
||||
const std::string_view& param = "") const override;
|
||||
|
||||
47
test/cctest/test_path.cc
Normal file
47
test/cctest/test_path.cc
Normal file
@ -0,0 +1,47 @@
|
||||
#include "debug_utils-inl.h"
|
||||
#include "env-inl.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "node_options.h"
|
||||
#include "node_test_fixture.h"
|
||||
#include "path.h"
|
||||
|
||||
using node::PathResolve;
|
||||
|
||||
class PathTest : public EnvironmentTestFixture {};
|
||||
|
||||
TEST_F(PathTest, PathResolve) {
|
||||
const v8::HandleScope handle_scope(isolate_);
|
||||
Argv argv;
|
||||
Env env{handle_scope, argv, node::EnvironmentFlags::kNoBrowserGlobals};
|
||||
auto cwd = (*env)->GetCwd((*env)->exec_path());
|
||||
#ifdef _WIN32
|
||||
EXPECT_EQ(PathResolve(*env, {"c:/blah\\blah", "d:/games", "c:../a"}),
|
||||
"c:\\blah\\a");
|
||||
EXPECT_EQ(PathResolve(*env, {"c:/ignore", "d:\\a/b\\c/d", "\\e.exe"}),
|
||||
"d:\\e.exe");
|
||||
EXPECT_EQ(PathResolve(*env, {"c:/ignore", "c:/some/file"}), "c:\\some\\file");
|
||||
EXPECT_EQ(PathResolve(*env, {"d:/ignore", "d:some/dir//"}),
|
||||
"d:\\ignore\\some\\dir");
|
||||
EXPECT_EQ(PathResolve(*env, {"."}), cwd);
|
||||
EXPECT_EQ(PathResolve(*env, {"//server/share", "..", "relative\\"}),
|
||||
"\\\\server\\share\\relative");
|
||||
EXPECT_EQ(PathResolve(*env, {"c:/", "//"}), "c:\\");
|
||||
EXPECT_EQ(PathResolve(*env, {"c:/", "//dir"}), "c:\\dir");
|
||||
EXPECT_EQ(PathResolve(*env, {"c:/", "//server/share"}),
|
||||
"\\\\server\\share\\");
|
||||
EXPECT_EQ(PathResolve(*env, {"c:/", "//server//share"}),
|
||||
"\\\\server\\share\\");
|
||||
EXPECT_EQ(PathResolve(*env, {"c:/", "///some//dir"}), "c:\\some\\dir");
|
||||
EXPECT_EQ(
|
||||
PathResolve(*env, {"C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js"}),
|
||||
"C:\\foo\\tmp.3\\cycles\\root.js");
|
||||
#else
|
||||
EXPECT_EQ(PathResolve(*env, {"/var/lib", "../", "file/"}), "/var/file");
|
||||
EXPECT_EQ(PathResolve(*env, {"/var/lib", "/../", "file/"}), "/file");
|
||||
EXPECT_EQ(PathResolve(*env, {"a/b/c/", "../../.."}), cwd);
|
||||
EXPECT_EQ(PathResolve(*env, {"."}), cwd);
|
||||
EXPECT_EQ(PathResolve(*env, {"/some/dir", ".", "/absolute/"}), "/absolute");
|
||||
EXPECT_EQ(PathResolve(*env, {"/foo/tmp.3/", "../tmp.3/cycles/root.js"}),
|
||||
"/foo/tmp.3/cycles/root.js");
|
||||
#endif
|
||||
}
|
||||
31
test/parallel/test-permission-fs-absolute-path.js
Normal file
31
test/parallel/test-permission-fs-absolute-path.js
Normal file
@ -0,0 +1,31 @@
|
||||
// Flags: --experimental-permission --allow-fs-read=* --allow-child-process
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const path = require('path');
|
||||
common.skipIfWorker();
|
||||
|
||||
const assert = require('assert');
|
||||
const { spawnSync } = require('child_process');
|
||||
|
||||
{
|
||||
// Relative path as CLI args are supported
|
||||
const { status, stdout } = spawnSync(
|
||||
process.execPath,
|
||||
[
|
||||
'--experimental-permission',
|
||||
'--allow-fs-read', '*',
|
||||
'--allow-fs-write', path.resolve('../fixtures/permission/deny/regular-file.md'),
|
||||
'-e',
|
||||
`
|
||||
const path = require("path");
|
||||
const absolutePath = path.resolve("../fixtures/permission/deny/regular-file.md");
|
||||
console.log(process.permission.has("fs.write", absolutePath));
|
||||
`,
|
||||
]
|
||||
);
|
||||
|
||||
const [fsWrite] = stdout.toString().split('\n');
|
||||
assert.strictEqual(fsWrite, 'true');
|
||||
assert.strictEqual(status, 0);
|
||||
}
|
||||
@ -8,7 +8,7 @@ const assert = require('assert');
|
||||
const { spawnSync } = require('child_process');
|
||||
|
||||
{
|
||||
// Relative path as CLI args are NOT supported yet
|
||||
// Relative path as CLI args are supported
|
||||
const { status, stdout } = spawnSync(
|
||||
process.execPath,
|
||||
[
|
||||
@ -25,6 +25,6 @@ const { spawnSync } = require('child_process');
|
||||
);
|
||||
|
||||
const [fsWrite] = stdout.toString().split('\n');
|
||||
assert.strictEqual(fsWrite, 'false');
|
||||
assert.strictEqual(fsWrite, 'true');
|
||||
assert.strictEqual(status, 0);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user