seabox 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.mocharc.json +6 -6
- package/LICENSE.MD +21 -21
- package/README.md +310 -310
- package/bin/seabox-rebuild.mjs +88 -88
- package/bin/seabox.mjs +150 -147
- package/lib/blob.mjs +104 -104
- package/lib/bootstrap.cjs +756 -756
- package/lib/build-cache.mjs +199 -199
- package/lib/build.mjs +77 -77
- package/lib/config.mjs +243 -243
- package/lib/crypto-assets.mjs +125 -125
- package/lib/diagnostics.mjs +203 -203
- package/lib/entry-bundler.mjs +64 -64
- package/lib/fetch-node.mjs +172 -172
- package/lib/index.mjs +26 -26
- package/lib/inject.mjs +106 -106
- package/lib/manifest.mjs +100 -100
- package/lib/multi-target-builder.mjs +697 -697
- package/lib/native-scanner.mjs +203 -203
- package/lib/obfuscate.mjs +51 -51
- package/lib/require-shim.mjs +113 -113
- package/lib/rolldown-bundler.mjs +411 -411
- package/lib/unsign.cjs +197 -169
- package/package.json +61 -61
package/lib/unsign.cjs
CHANGED
|
@@ -1,169 +1,197 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* unsign.js
|
|
3
|
-
* Remove code signatures from executables before injection.
|
|
4
|
-
* This prevents signature corruption during postject injection.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { execFile } = require('child_process');
|
|
8
|
-
const { promisify } = require('util');
|
|
9
|
-
|
|
10
|
-
const execFileAsync = promisify(execFile);
|
|
11
|
-
|
|
12
|
-
// Simple verbose logging flag (set by inject.mjs)
|
|
13
|
-
let verboseMode = false;
|
|
14
|
-
function setVerbose(enabled) {
|
|
15
|
-
verboseMode = enabled;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function logVerbose(message, indent = 2) {
|
|
19
|
-
if (verboseMode) {
|
|
20
|
-
console.log(' '.repeat(indent) + message);
|
|
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
|
-
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (
|
|
156
|
-
logVerbose(`[
|
|
157
|
-
|
|
158
|
-
logVerbose(`
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* unsign.js
|
|
3
|
+
* Remove code signatures from executables before injection.
|
|
4
|
+
* This prevents signature corruption during postject injection.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { execFile } = require('child_process');
|
|
8
|
+
const { promisify } = require('util');
|
|
9
|
+
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
|
|
12
|
+
// Simple verbose logging flag (set by inject.mjs)
|
|
13
|
+
let verboseMode = false;
|
|
14
|
+
function setVerbose(enabled) {
|
|
15
|
+
verboseMode = enabled;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function logVerbose(message, indent = 2) {
|
|
19
|
+
if (verboseMode) {
|
|
20
|
+
console.log(' '.repeat(indent) + message);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function delay(ms) {
|
|
25
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check if a signing tool is available on the system.
|
|
30
|
+
* @param {string} platform - Target platform (win32, linux, darwin)
|
|
31
|
+
* @returns {Promise<{available: boolean, tool: string|null}>}
|
|
32
|
+
*/
|
|
33
|
+
async function checkSignToolAvailability(platform) {
|
|
34
|
+
const tools = {
|
|
35
|
+
win32: 'signtool.exe',
|
|
36
|
+
darwin: 'codesign',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const tool = tools[platform];
|
|
40
|
+
if (!tool) {
|
|
41
|
+
return { available: false, tool: null };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
// Try to execute the tool with a version/help flag to check availability
|
|
46
|
+
if (platform === 'win32') {
|
|
47
|
+
await execFileAsync('where', ['signtool.exe']);
|
|
48
|
+
} else if (platform === 'darwin') {
|
|
49
|
+
await execFileAsync('which', ['codesign']);
|
|
50
|
+
}
|
|
51
|
+
return { available: true, tool };
|
|
52
|
+
} catch (error) {
|
|
53
|
+
return { available: false, tool };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Remove signature from a Windows executable using signtool.
|
|
59
|
+
* @param {string} exePath - Path to the executable
|
|
60
|
+
* @returns {Promise<{success: boolean, message: string}>}
|
|
61
|
+
*/
|
|
62
|
+
async function removeWindowsSignature(exePath) {
|
|
63
|
+
let lastError = null;
|
|
64
|
+
|
|
65
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
66
|
+
try {
|
|
67
|
+
const { stdout, stderr } = await execFileAsync('signtool.exe', ['remove', '/s', exePath]);
|
|
68
|
+
|
|
69
|
+
const output = (stdout + stderr).toLowerCase();
|
|
70
|
+
|
|
71
|
+
// Check if successfully removed
|
|
72
|
+
if (output.includes('successfully')) {
|
|
73
|
+
return { success: true, message: 'Signature removed successfully' };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check if there was no signature
|
|
77
|
+
if (output.includes('no signature') || output.includes('not signed')) {
|
|
78
|
+
return { success: true, message: 'Binary was not signed (no signature to remove)' };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { success: true, message: stdout || 'Signature removal completed' };
|
|
82
|
+
} catch (error) {
|
|
83
|
+
const errorMsg = error.message || error.stderr || '';
|
|
84
|
+
|
|
85
|
+
// Not an error if there was no signature to begin with
|
|
86
|
+
if (errorMsg.includes('No signature') || errorMsg.includes('not signed')) {
|
|
87
|
+
return { success: true, message: 'Binary was not signed (no signature to remove)' };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
lastError = errorMsg;
|
|
91
|
+
|
|
92
|
+
// If not the last attempt, wait before retrying
|
|
93
|
+
if (attempt < 3) {
|
|
94
|
+
await delay(500);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return { success: false, message: `Failed to remove signature: ${lastError}` };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Remove signature from a macOS executable using codesign.
|
|
105
|
+
* @param {string} exePath - Path to the executable
|
|
106
|
+
* @returns {Promise<{success: boolean, message: string}>}
|
|
107
|
+
*/
|
|
108
|
+
async function removeMacSignature(exePath) {
|
|
109
|
+
let lastError = null;
|
|
110
|
+
|
|
111
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
112
|
+
try {
|
|
113
|
+
// On macOS, use --remove-signature flag
|
|
114
|
+
const { stdout, stderr } = await execFileAsync('codesign', ['--remove-signature', exePath]);
|
|
115
|
+
|
|
116
|
+
return { success: true, message: 'Signature removed successfully' };
|
|
117
|
+
} catch (error) {
|
|
118
|
+
const errorMsg = error.message || error.stderr || '';
|
|
119
|
+
|
|
120
|
+
// Not an error if there was no signature
|
|
121
|
+
if (errorMsg.includes('not signed') || errorMsg.includes('no signature')) {
|
|
122
|
+
return { success: true, message: 'Binary was not signed (no signature to remove)' };
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
lastError = errorMsg;
|
|
126
|
+
|
|
127
|
+
// If not the last attempt, wait before retrying
|
|
128
|
+
if (attempt < 3) {
|
|
129
|
+
await delay(500);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return { success: false, message: `Failed to remove signature: ${lastError}` };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Remove code signature from an executable before injection.
|
|
141
|
+
* This is critical to prevent signature corruption during postject injection.
|
|
142
|
+
* @param {string} exePath - Path to the executable
|
|
143
|
+
* @param {string} platform - Target platform (win32, linux, darwin)
|
|
144
|
+
* @returns {Promise<void>}
|
|
145
|
+
*/
|
|
146
|
+
async function removeSignature(exePath, platform) {
|
|
147
|
+
// Linux binaries are typically not signed, so skip signature removal
|
|
148
|
+
if (platform === 'linux') {
|
|
149
|
+
logVerbose('Skipping signature removal (Linux binaries are typically unsigned)');
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const { available, tool } = await checkSignToolAvailability(platform);
|
|
154
|
+
|
|
155
|
+
if (!available) {
|
|
156
|
+
logVerbose(`[!] Warning: Signature removal tool not found for ${platform}`);
|
|
157
|
+
logVerbose(`Tool needed: ${tool || 'unknown'}`, 2);
|
|
158
|
+
logVerbose(`The binary may have an existing signature that will be corrupted during injection.`, 2);
|
|
159
|
+
|
|
160
|
+
if (platform === 'win32') {
|
|
161
|
+
logVerbose(`Install Windows SDK to get signtool.exe`, 2);
|
|
162
|
+
logVerbose(`Download from: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/`, 2);
|
|
163
|
+
} else if (platform === 'darwin') {
|
|
164
|
+
logVerbose(`Install Xcode Command Line Tools to get codesign`, 2);
|
|
165
|
+
logVerbose(`Run: xcode-select --install`, 2);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
logVerbose(`Found ${tool}, attempting to remove signature...`);
|
|
172
|
+
|
|
173
|
+
let result;
|
|
174
|
+
if (platform === 'win32') {
|
|
175
|
+
result = await removeWindowsSignature(exePath);
|
|
176
|
+
} else if (platform === 'darwin') {
|
|
177
|
+
result = await removeMacSignature(exePath);
|
|
178
|
+
} else {
|
|
179
|
+
logVerbose(`[!] Warning: Unsupported platform for signature removal: ${platform}`);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (result.success) {
|
|
184
|
+
logVerbose(`[✓] ${result.message}`);
|
|
185
|
+
} else {
|
|
186
|
+
logVerbose(`[!] Warning: ${result.message}`);
|
|
187
|
+
logVerbose(`Continuing anyway, but the executable may have signature issues.`, 2);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
module.exports = {
|
|
192
|
+
removeSignature,
|
|
193
|
+
checkSignToolAvailability,
|
|
194
|
+
removeWindowsSignature,
|
|
195
|
+
removeMacSignature,
|
|
196
|
+
setVerbose,
|
|
197
|
+
};
|
package/package.json
CHANGED
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "seabox",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Node.js Single Executable Application (SEA) builder tool with native and library extraction",
|
|
5
|
-
"main": "lib/index.mjs",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"seabox": "bin/seabox.mjs"
|
|
9
|
-
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"clean": "rimraf dist",
|
|
12
|
-
"prepublishOnly": "",
|
|
13
|
-
"test": "mocha"
|
|
14
|
-
},
|
|
15
|
-
"keywords": [
|
|
16
|
-
"sea",
|
|
17
|
-
"build",
|
|
18
|
-
"builder",
|
|
19
|
-
"single-executable",
|
|
20
|
-
"SEA",
|
|
21
|
-
"native",
|
|
22
|
-
"module",
|
|
23
|
-
"pkg",
|
|
24
|
-
"dll",
|
|
25
|
-
"packaging",
|
|
26
|
-
"node",
|
|
27
|
-
"postject"
|
|
28
|
-
],
|
|
29
|
-
"author": "Meirion Hughes",
|
|
30
|
-
"license": "MIT",
|
|
31
|
-
"repository": {
|
|
32
|
-
"type": "git",
|
|
33
|
-
"url": "https://github.com/MeirionHughes/seabox"
|
|
34
|
-
},
|
|
35
|
-
"homepage": "https://github.com/MeirionHughes/seabox",
|
|
36
|
-
"dependencies": {
|
|
37
|
-
"adm-zip": "^0.5.16",
|
|
38
|
-
"glob": "^10.0.0",
|
|
39
|
-
"postject": "^1.0.0-alpha.6",
|
|
40
|
-
"rolldown": "^1.0.0-beta.50",
|
|
41
|
-
"tar": "^6.2.1"
|
|
42
|
-
},
|
|
43
|
-
"peerDependencies": {
|
|
44
|
-
"rcedit": "^4.0.1"
|
|
45
|
-
},
|
|
46
|
-
"peerDependenciesMeta": {
|
|
47
|
-
"rcedit": {
|
|
48
|
-
"optional": true
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"chai": "^6.2.1",
|
|
53
|
-
"javascript-obfuscator": "^4.1.1",
|
|
54
|
-
"mocha": "^11.7.5",
|
|
55
|
-
"node-api-headers": "^1.2.0",
|
|
56
|
-
"rimraf": "^6.0.1"
|
|
57
|
-
},
|
|
58
|
-
"engines": {
|
|
59
|
-
"node": ">=18.0.0"
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "seabox",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Node.js Single Executable Application (SEA) builder tool with native and library extraction",
|
|
5
|
+
"main": "lib/index.mjs",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"seabox": "bin/seabox.mjs"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"clean": "rimraf dist",
|
|
12
|
+
"prepublishOnly": "",
|
|
13
|
+
"test": "mocha"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"sea",
|
|
17
|
+
"build",
|
|
18
|
+
"builder",
|
|
19
|
+
"single-executable",
|
|
20
|
+
"SEA",
|
|
21
|
+
"native",
|
|
22
|
+
"module",
|
|
23
|
+
"pkg",
|
|
24
|
+
"dll",
|
|
25
|
+
"packaging",
|
|
26
|
+
"node",
|
|
27
|
+
"postject"
|
|
28
|
+
],
|
|
29
|
+
"author": "Meirion Hughes",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/MeirionHughes/seabox"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/MeirionHughes/seabox",
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"adm-zip": "^0.5.16",
|
|
38
|
+
"glob": "^10.0.0",
|
|
39
|
+
"postject": "^1.0.0-alpha.6",
|
|
40
|
+
"rolldown": "^1.0.0-beta.50",
|
|
41
|
+
"tar": "^6.2.1"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"rcedit": "^4.0.1"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"rcedit": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"chai": "^6.2.1",
|
|
53
|
+
"javascript-obfuscator": "^4.1.1",
|
|
54
|
+
"mocha": "^11.7.5",
|
|
55
|
+
"node-api-headers": "^1.2.0",
|
|
56
|
+
"rimraf": "^6.0.1"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18.0.0"
|
|
60
|
+
}
|
|
61
|
+
}
|