Skip to content

Commit 57d9fc3

Browse files
committed
Manual permissions control
1 parent e16f394 commit 57d9fc3

4 files changed

Lines changed: 229 additions & 103 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545
run: |
4646
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
4747
$startInfo.FileName = "${{ steps.vsinst.outputs.cmd }}"
48-
$startInfo.Arguments = 'modify --installPath "${{ steps.vs.outputs.path }}" --add Microsoft.VisualStudio.Component.VC.14.36.17.6.x86.x64 --passive --norestart --wait --noUpdateInstaller'
48+
$startInfo.Arguments = 'modify --installPath "${{ steps.vs.outputs.path }}" --add Microsoft.VisualStudio.Component.VC.14.36.17.6.x86.x64 --quiet --norestart --wait --noUpdateInstaller'
4949
$process = New-Object System.Diagnostics.Process
5050
$process.StartInfo = $startInfo
5151
$process.Start()

build-windows.bat

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,90 @@
11
@echo off
2+
setlocal EnableExtensions EnableDelayedExpansion
3+
4+
rem Enter the Node source folder
25
pushd node
36

7+
rem Apply local patches, if any
48
for %%f in (../patches/*.patch) do (
59
echo Applying %%f...
610
git apply --reject --whitespace=fix "../patches/%%f"
711
)
812

9-
python ../HandleScope.py src
13+
rem Build Release and Debug DLLs (clang-cl, no tests, no npm)
14+
call vcbuild.bat release x64 dll no-cctest clang-cl nonpm
15+
call vcbuild.bat debug x64 dll no-cctest clang-cl nonpm
16+
17+
rem Staging directories for packaging
18+
set STAGE_ROOT=..\out
19+
set STAGE_REL=%STAGE_ROOT%\Release
20+
set STAGE_REL_LIB=%STAGE_REL%\lib
21+
set STAGE_DBG=%STAGE_ROOT%\Debug
22+
set STAGE_DBG_LIB=%STAGE_DBG%\lib
23+
24+
if not exist "%STAGE_REL%" mkdir "%STAGE_REL%"
25+
if not exist "%STAGE_REL_LIB%" mkdir "%STAGE_REL_LIB%"
26+
if not exist "%STAGE_DBG%" mkdir "%STAGE_DBG%"
27+
if not exist "%STAGE_DBG_LIB%" mkdir "%STAGE_DBG_LIB%"
28+
29+
rem Helper to copy headers (*.h, *.hpp) recursively
30+
rem Usage: call :copy_headers "src_dir" "dest_dir"
31+
goto :after_functions
32+
:copy_headers
33+
set SRC=%~1
34+
set DST=%~2
35+
if not exist "%DST%" mkdir "%DST%"
36+
rem robocopy returns codes <8 for success; ignore non-fatal codes
37+
robocopy "%SRC%" "%DST%" *.h /S >nul & if errorlevel 8 exit /b %ERRORLEVEL%
38+
robocopy "%SRC%" "%DST%" *.hpp /S >nul & if errorlevel 8 exit /b %ERRORLEVEL%
39+
exit /b 0
40+
:after_functions
41+
42+
echo Collect includes (node, uv, v8, openssl) into include/node
43+
set INC_REL=%STAGE_REL%\include\node
44+
set INC_DBG=%STAGE_DBG%\include\node
45+
46+
call :copy_headers "src" "%INC_REL%" || goto :fail
47+
call :copy_headers "deps\uv\include" "%INC_REL%\uv\include" || goto :fail
48+
call :copy_headers "deps\v8\include" "%INC_REL%\v8\include" || goto :fail
49+
call :copy_headers "deps\openssl" "%INC_REL%\openssl" || goto :fail
50+
51+
call :copy_headers "src" "%INC_DBG%" || goto :fail
52+
call :copy_headers "deps\uv\include" "%INC_DBG%\uv\include" || goto :fail
53+
call :copy_headers "deps\v8\include" "%INC_DBG%\v8\include" || goto :fail
54+
call :copy_headers "deps\openssl" "%INC_DBG%\openssl" || goto :fail
55+
56+
echo Locate built artifacts and copy/rename to expected names
57+
echo %CWD%
58+
set REL_BUILD=out\Release
59+
set DBG_BUILD=out\Debug
60+
61+
copy /Y "%REL_BUILD%\libnode22.dll" "%STAGE_REL%\lib\libnode22.dll" >nul
62+
copy /Y "%REL_BUILD%\libnode22.lib" "%STAGE_REL%\lib\libnode22.lib" >nul
63+
copy /Y "%REL_BUILD%\libnode22.pdb" "%STAGE_REL%\lib\libnode22.pdb" >nul
64+
65+
copy /Y "%DBG_BUILD%\libnode22.dll" "%STAGE_DBG%\lib\libnode22.dll" >nul
66+
copy /Y "%DBG_BUILD%\libnode22.lib" "%STAGE_DBG%\lib\libnode22.lib" >nul
67+
copy /Y "%DBG_BUILD%\libnode22.pdb" "%STAGE_DBG%\lib\libnode22.pdb" >nul
68+
69+
echo Create tar.xz packages if tar (bsdtar) is available
70+
where tar >nul 2>nul
71+
if %ERRORLEVEL% EQU 0 (
72+
echo Creating archives...
73+
tar -cJf "%STAGE_ROOT%\libnode22-release.tar.xz" -C "%STAGE_REL%" .
74+
tar -cJf "%STAGE_ROOT%\libnode22-debug.tar.xz" -C "%STAGE_DBG%" .
75+
echo Done: %STAGE_ROOT%\libnode22-release.tar.xz
76+
echo Done: %STAGE_ROOT%\libnode22-debug.tar.xz
77+
) else (
78+
echo WARN: 'tar' not found. Skipping archive creation. Artifacts left in:
79+
echo %STAGE_REL%
80+
echo %STAGE_DBG%
81+
)
82+
83+
popd
84+
echo Windows Node build and packaging completed.
85+
exit /b 0
1086

11-
vcbuild.bat release x64 dll no-cctest clang-cl nonpm
87+
:fail
88+
popd
89+
echo Build failed. See output above.
90+
exit /b 1

patches/handle_scope.patch

Lines changed: 40 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,47 @@
1-
diff --git forkSrcPrefix/src/node.h forkDstPrefix/src/node.h
2-
index 60598f54114b2424f10706e57d8aa50c4634bcb0..9213adb06dd45f521867591ff9a4af70096802de 100644
3-
--- forkSrcPrefix/src/node.h
4-
+++ forkDstPrefix/src/node.h
5-
@@ -228,6 +228,67 @@ namespace node {
1+
diff --git forkSrcPrefix/deps/v8/src/api/api.cc forkDstPrefix/deps/v8/src/api/api.cc
2+
index 2dd476dda34f1cfe3a75b7895009af24963372f2..6476204733a8aa87c4681dbeb5fee12db54e529d 100644
3+
--- forkSrcPrefix/deps/v8/src/api/api.cc
4+
+++ forkDstPrefix/deps/v8/src/api/api.cc
5+
@@ -883,7 +883,21 @@ void InternalFieldOutOfBounds(int index) {
66

7-
class IsolateData;
8-
class Environment;
9-
+
10-
+class ScopeCB
11-
+{
12-
+ v8::Isolate* m_isolate;
13-
+public:
14-
+ inline ScopeCB(v8::Isolate* isolate) : m_isolate(isolate) {
15-
+ if(g_enterScopeCB) {
16-
+ g_enterScopeCB(isolate);
17-
+ }
18-
+ }
19-
+
20-
+ inline ~ScopeCB() {
21-
+ if(g_leaveScopeCB) {
22-
+ g_leaveScopeCB(m_isolate);
23-
+ }
24-
+ }
25-
+
26-
+ inline static std::function<void(v8::Isolate*)> g_enterScopeCB;
27-
+ inline static std::function<void(v8::Isolate*)> g_leaveScopeCB;
28-
+};
29-
+
30-
+NODE_EXTERN void SetScopeHandler(const std::function<void(v8::Isolate*)>& enter,
31-
+ const std::function<void(v8::Isolate*)>& exit);
32-
+
33-
+class NodeHandleScope
34-
+{
35-
+ ScopeCB m_scopeCB;
36-
+ v8::HandleScope m_handleScope;
37-
+public:
38-
+ inline NodeHandleScope(v8::Isolate* isolate) : m_scopeCB(isolate), m_handleScope(isolate) {}
39-
+ inline ~NodeHandleScope() = default;
40-
+};
41-
+
42-
+class NodeEscapableHandleScope
43-
+{
44-
+ ScopeCB m_scopeCB;
45-
+ v8::EscapableHandleScope m_handleScope;
46-
+public:
47-
+ inline NodeEscapableHandleScope(v8::Isolate* isolate) : m_scopeCB(isolate), m_handleScope(isolate) {}
48-
+ inline ~NodeEscapableHandleScope() = default;
49-
+
50-
+ template <class T>
51-
+ inline v8::Local<T> Escape(v8::Local<T> value) {
52-
+ return m_handleScope.Escape(value);
53-
+ }
7+
// --- H a n d l e s ---
8+
9+
-HandleScope::HandleScope(Isolate* v8_isolate) { Initialize(v8_isolate); }
10+
+static std::function<void(Isolate*)> g_enterScopeCB;
11+
+static std::function<void(Isolate*)> g_leaveScopeCB;
12+
+
13+
+V8_EXPORT void SetScopeHandler(const std::function<void(Isolate*)>& enter,
14+
+ const std::function<void(Isolate*)>& exit) {
15+
+ g_enterScopeCB = enter;
16+
+ g_leaveScopeCB = exit;
17+
+}
5418
+
55-
+ template <class T>
56-
+ inline v8::MaybeLocal<T> EscapeMaybe(v8::MaybeLocal<T> value) {
57-
+ return m_handleScope.EscapeMaybe(value);
19+
+HandleScope::HandleScope(Isolate* v8_isolate) {
20+
+ if(g_enterScopeCB) {
21+
+ g_enterScopeCB(v8_isolate);
5822
+ }
59-
+};
60-
+
61-
+class NodeSealHandleScope
62-
+{
63-
+ ScopeCB m_scopeCB;
64-
+ v8::SealHandleScope m_handleScope;
65-
+public:
66-
+ inline NodeSealHandleScope(v8::Isolate* isolate) : m_scopeCB(isolate), m_handleScope(isolate) {}
67-
+ inline ~NodeSealHandleScope() = default;
68-
+};
69-
+
70-
class MultiIsolatePlatform;
71-
class InitializationResultImpl;
72-
73-
diff --git forkSrcPrefix/src/node.cc forkDstPrefix/src/node.cc
74-
index 1a2a43bdd37441400323a800c147fcb89f0d549a..81f15f01e2a59f3752254a768f6a58d4286a23fc 100644
75-
--- forkSrcPrefix/src/node.cc
76-
+++ forkDstPrefix/src/node.cc
77-
@@ -290,7 +290,7 @@ void Environment::InitializeDiagnostics() {
78-
79-
static
80-
MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
81-
- EscapableHandleScope scope(env->isolate());
82-
+ NodeEscapableHandleScope scope(env->isolate());
83-
CHECK_NOT_NULL(main_script_id);
84-
Realm* realm = env->principal_realm();
85-
86-
@@ -338,7 +338,7 @@ MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
87-
// Only snapshot builder or embedder applications set the
88-
// callback.
89-
if (cb != nullptr) {
90-
- EscapableHandleScope scope(env->isolate());
91-
+ NodeEscapableHandleScope scope(env->isolate());
23+
+ Initialize(v8_isolate);
24+
+}
9225

93-
Local<Value> result;
94-
if (env->isolate_data()->is_building_snapshot()) {
95-
@@ -1548,6 +1548,12 @@ int Stop(Environment* env, StopFlags::Flags flags) {
96-
return 0;
26+
void HandleScope::Initialize(Isolate* v8_isolate) {
27+
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
28+
@@ -908,6 +922,9 @@ void HandleScope::Initialize(Isolate* v8_isolate) {
9729
}
9830

99-
+void SetScopeHandler(const std::function<void(v8::Isolate*)>& enter,
100-
+ const std::function<void(v8::Isolate*)>& exit) {
101-
+ ScopeCB::g_enterScopeCB = enter;
102-
+ ScopeCB::g_leaveScopeCB = exit;
103-
+}
104-
+
105-
} // namespace node
31+
HandleScope::~HandleScope() {
32+
+ if(g_leaveScopeCB) {
33+
+ g_leaveScopeCB(reinterpret_cast<Isolate*>(i_isolate_));
34+
+ }
35+
#ifdef V8_ENABLE_CHECKS
36+
CHECK_EQ(scope_level_, i_isolate_->handle_scope_data()->level);
37+
#endif
38+
@@ -938,6 +955,9 @@ i::Address* HandleScope::CreateHandleForCurrentIsolate(i::Address value) {
39+
#endif // V8_ENABLE_DIRECT_LOCAL
10640

107-
#if !HAVE_INSPECTOR
41+
EscapableHandleScopeBase::EscapableHandleScopeBase(Isolate* v8_isolate) {
42+
+ if(g_enterScopeCB) {
43+
+ g_enterScopeCB(v8_isolate);
44+
+ }
45+
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
46+
escape_slot_ = CreateHandle(
47+
i_isolate, i::ReadOnlyRoots(i_isolate).the_hole_value().ptr());
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
diff --git forkSrcPrefix/src/node.h forkDstPrefix/src/node.h
2+
index 60598f54114b2424f10706e57d8aa50c4634bcb0..b3ebb94dd63ee7edaf8c80f0759ef43d690d54c2 100644
3+
--- forkSrcPrefix/src/node.h
4+
+++ forkDstPrefix/src/node.h
5+
@@ -137,6 +137,12 @@ class TracingController;
6+
7+
}
8+
9+
+namespace permission {
10+
+
11+
+enum class PermissionScope;
12+
+
13+
+} // namespace permission
14+
+
15+
NODE_EXTERN v8::Local<v8::Value> ErrnoException(v8::Isolate* isolate,
16+
int errorno,
17+
const char* syscall = nullptr,
18+
@@ -769,6 +775,12 @@ NODE_EXTERN v8::MaybeLocal<v8::Value> LoadEnvironment(
19+
EmbedderPreloadCallback preload = nullptr);
20+
NODE_EXTERN void FreeEnvironment(Environment* env);
21+
22+
+// Set a callback for permission control
23+
+NODE_EXTERN void SetPermissionHandler(Environment* env,
24+
+ std::function<bool(Environment*,
25+
+ permission::PermissionScope,
26+
+ const std::string_view&)>&& handler);
27+
+
28+
// Set a callback that is called when process.exit() is called from JS,
29+
// overriding the default handler.
30+
// It receives the Environment* instance and the exit code as arguments.
31+
diff --git forkSrcPrefix/src/api/environment.cc forkDstPrefix/src/api/environment.cc
32+
index ad323fc800a33c010b0504a4aa55c107498dee26..ec3d61159060f6efbebff3f3a2473a32d11c366a 100644
33+
--- forkSrcPrefix/src/api/environment.cc
34+
+++ forkDstPrefix/src/api/environment.cc
35+
@@ -922,4 +922,11 @@ void SetProcessExitHandler(Environment* env,
36+
});
37+
}
38+
39+
+void SetPermissionHandler(Environment* env,
40+
+ std::function<bool(Environment*,
41+
+ permission::PermissionScope,
42+
+ const std::string_view&)>&& handler) {
43+
+ env->permission()->EnableManualPermissionControl(std::move(handler));
44+
+}
45+
+
46+
} // namespace node
47+
diff --git forkSrcPrefix/src/permission/permission.cc forkDstPrefix/src/permission/permission.cc
48+
index 7c84aa044dbbf58e2ae05f29d2cfad5502ea745e..c47992d2b3cdc068e1b74bc36767ded0e1c25acb 100644
49+
--- forkSrcPrefix/src/permission/permission.cc
50+
+++ forkDstPrefix/src/permission/permission.cc
51+
@@ -152,6 +152,12 @@ void Permission::EnablePermissions() {
52+
}
53+
}
54+
55+
+void Permission::EnableManualPermissionControl(
56+
+ PermissionCheckCallback&& permission_check_callback) {
57+
+ enabled_ = true;
58+
+ permission_check_callback_ = std::move(permission_check_callback);
59+
+}
60+
+
61+
void Permission::Apply(Environment* env,
62+
const std::vector<std::string>& allow,
63+
PermissionScope scope) {
64+
diff --git forkSrcPrefix/src/permission/permission.h forkDstPrefix/src/permission/permission.h
65+
index 8e5bb87803656f857602736abbb077ec2e192589..3c457293e95fbe6c275829e1c88fa46ab4776703 100644
66+
--- forkSrcPrefix/src/permission/permission.h
67+
+++ forkDstPrefix/src/permission/permission.h
68+
@@ -47,6 +47,11 @@ namespace permission {
69+
70+
class Permission {
71+
public:
72+
+ using PermissionCheckCallback =
73+
+ std::function<bool(Environment* env,
74+
+ PermissionScope permission,
75+
+ const std::string_view& resource)>;
76+
+
77+
Permission();
78+
79+
FORCE_INLINE bool is_granted(Environment* env,
80+
@@ -55,6 +60,9 @@ class Permission {
81+
if (!enabled_) [[likely]] {
82+
return true;
83+
}
84+
+ if (permission_check_callback_) {
85+
+ return permission_check_callback_(env, permission, res);
86+
+ }
87+
return is_scope_granted(env, permission, res);
88+
}
89+
90+
@@ -76,6 +84,9 @@ class Permission {
91+
PermissionScope scope);
92+
void EnablePermissions();
93+
94+
+ void EnableManualPermissionControl(
95+
+ PermissionCheckCallback&& permission_check_callback);
96+
+
97+
private:
98+
COLD_NOINLINE bool is_scope_granted(Environment* env,
99+
const PermissionScope permission,
100+
@@ -89,6 +100,7 @@ class Permission {
101+
102+
std::unordered_map<PermissionScope, std::shared_ptr<PermissionBase>> nodes_;
103+
bool enabled_;
104+
+ PermissionCheckCallback permission_check_callback_;
105+
};
106+
107+
} // namespace permission

0 commit comments

Comments
 (0)