|
1 | 1 | #!/usr/bin/env node |
2 | 2 |
|
3 | 3 | /** |
4 | | - * Post-build script to remove the NAPI_RS_NATIVE_LIBRARY_PATH environment |
5 | | - * variable check from the generated index.js file. |
| 4 | + * Post-build script to replace NAPI-RS generated loader with a minimal, |
| 5 | + * security-friendly version. |
6 | 6 | * |
7 | | - * This eliminates the "unanalyzable dynamic import" warning when publishing to JSR. |
| 7 | + * This eliminates Socket.dev security concerns: |
| 8 | + * - Removes shell access (child_process.execSync) |
| 9 | + * - Removes filesystem reads (/usr/bin/ldd) |
| 10 | + * - Removes environment variable checks (NAPI_RS_ENFORCE_VERSION_CHECK) |
| 11 | + * - Removes musl detection from platform packages (detection moved to index.ts) |
| 12 | + * |
| 13 | + * Platform Support: |
| 14 | + * - macOS: darwin-x64, darwin-arm64 |
| 15 | + * - Windows: win32-x64-msvc, win32-arm64-msvc |
| 16 | + * - Linux: linux-x64-gnu, linux-arm64-gnu, linux-x64-musl, linux-arm64-musl |
| 17 | + * |
| 18 | + * Note: Musl detection is handled in src/index.ts using process.report API |
| 19 | + * (no shell/filesystem access), keeping platform packages clean and secure. |
8 | 20 | */ |
9 | 21 |
|
10 | 22 | import { existsSync, readFileSync, writeFileSync, readdirSync } from "fs"; |
@@ -36,51 +48,96 @@ function getIndexPaths() { |
36 | 48 | return platforms.map(platform => join(npmDir, platform, "index.js")); |
37 | 49 | } |
38 | 50 |
|
39 | | -const indexPaths = getIndexPaths(); |
| 51 | +/** |
| 52 | + * Extract exported symbols from the original generated file |
| 53 | + */ |
| 54 | +function extractExports(content) { |
| 55 | + const exportMatch = content.match(/const\s*\{([^}]+)\}\s*=\s*nativeBinding/); |
| 56 | + if (!exportMatch) return null; |
| 57 | + |
| 58 | + const symbols = exportMatch[1] |
| 59 | + .split(",") |
| 60 | + .map(s => s.trim()) |
| 61 | + .filter(Boolean); |
| 62 | + |
| 63 | + return symbols; |
| 64 | +} |
| 65 | + |
| 66 | +/** |
| 67 | + * Generate a minimal, secure loader for the platform package |
| 68 | + */ |
| 69 | +function generateMinimalLoader(platform, exports) { |
| 70 | + const binaryName = `printers.${platform}.node`; |
| 71 | + |
| 72 | + return `// prettier-ignore |
| 73 | +/* eslint-disable */ |
| 74 | +/* Minimal secure loader - generated by remove-env-check.js */ |
| 75 | +
|
| 76 | +import { createRequire } from 'node:module' |
| 77 | +const require = createRequire(import.meta.url) |
| 78 | +
|
| 79 | +let nativeBinding = null |
| 80 | +
|
| 81 | +try { |
| 82 | + nativeBinding = require('./${binaryName}') |
| 83 | +} catch (localErr) { |
| 84 | + try { |
| 85 | + nativeBinding = require('@printers/printers-${platform}') |
| 86 | + } catch (packageErr) { |
| 87 | + throw new Error( |
| 88 | + \`Failed to load native binding for ${platform}. \` + |
| 89 | + \`Please try reinstalling the package.\`, |
| 90 | + { cause: [localErr, packageErr] } |
| 91 | + ) |
| 92 | + } |
| 93 | +} |
| 94 | +
|
| 95 | +const { ${exports.join(", ")} } = nativeBinding |
| 96 | +${exports.map(sym => `export { ${sym} }`).join("\n")} |
| 97 | +`; |
| 98 | +} |
40 | 99 |
|
41 | 100 | function processIndexFile(indexPath) { |
42 | 101 | if (!existsSync(indexPath)) { |
43 | | - console.log(`⚠️ ${indexPath} not found - skipping env check removal`); |
| 102 | + console.log(`⚠️ ${indexPath} not found - skipping`); |
44 | 103 | return false; |
45 | 104 | } |
46 | 105 |
|
47 | 106 | try { |
48 | 107 | const content = readFileSync(indexPath, "utf-8"); |
49 | 108 |
|
50 | | - // Remove TypeScript-specific comments that cause issues with Deno |
51 | | - let modifiedContent = content.replace(/\/\/\s*@ts-nocheck\s*\n/g, ""); |
52 | | - |
53 | | - // Remove the entire NAPI_RS_NATIVE_LIBRARY_PATH check block |
54 | | - // This regex matches the if block and its else-if continuation |
55 | | - // Updated to handle the current NAPI-RS structure |
56 | | - modifiedContent = modifiedContent.replace( |
57 | | - /\s+if\s+\(process\.env\.NAPI_RS_NATIVE_LIBRARY_PATH\)\s+\{[\s\S]*?\n\s*\}\s*else\s+if\s+\(process\.platform\s*===\s*['"]android['"]\)/, |
58 | | - "\n if (process.platform === 'android')" |
59 | | - ); |
60 | | - |
61 | | - if (content !== modifiedContent) { |
62 | | - writeFileSync(indexPath, modifiedContent); |
63 | | - console.log( |
64 | | - `✅ Removed NAPI_RS_NATIVE_LIBRARY_PATH check from ${indexPath}` |
65 | | - ); |
66 | | - return true; |
67 | | - } else { |
68 | | - console.log( |
69 | | - `ℹ️ NAPI_RS_NATIVE_LIBRARY_PATH check not found or already removed in ${indexPath}` |
70 | | - ); |
| 109 | + // Extract platform from path (e.g., "darwin-arm64" from "npm/darwin-arm64/index.js") |
| 110 | + const platformMatch = indexPath.match(/npm[/\\]([^/\\]+)[/\\]index\.js/); |
| 111 | + if (!platformMatch) { |
| 112 | + console.log(`⚠️ Could not extract platform from ${indexPath}`); |
71 | 113 | return false; |
72 | 114 | } |
| 115 | + const platform = platformMatch[1]; |
| 116 | + |
| 117 | + // Extract exported symbols |
| 118 | + const exports = extractExports(content); |
| 119 | + if (!exports) { |
| 120 | + console.log(`⚠️ Could not extract exports from ${indexPath}`); |
| 121 | + return false; |
| 122 | + } |
| 123 | + |
| 124 | + // Generate minimal loader |
| 125 | + const minimalContent = generateMinimalLoader(platform, exports); |
| 126 | + |
| 127 | + writeFileSync(indexPath, minimalContent); |
| 128 | + console.log(`✅ Replaced loader with minimal version: ${indexPath}`); |
| 129 | + return true; |
73 | 130 | } catch (error) { |
74 | 131 | console.error(`❌ Error processing ${indexPath}:`, error); |
75 | 132 | throw error; |
76 | 133 | } |
77 | 134 | } |
78 | 135 |
|
| 136 | +const indexPaths = getIndexPaths(); |
| 137 | + |
79 | 138 | try { |
80 | 139 | if (indexPaths.length === 0) { |
81 | | - console.log( |
82 | | - "⚠️ No npm platform directories found - skipping env check removal" |
83 | | - ); |
| 140 | + console.log("⚠️ No npm platform directories found"); |
84 | 141 | process.exit(0); |
85 | 142 | } |
86 | 143 |
|
|
0 commit comments