UNPKG

@socketsecurity/lib

Version:

Core utilities and infrastructure for Socket.dev security tools

429 lines (428 loc) 14.3 kB
"use strict"; /* Socket Lib - Built with esbuild */ var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var dlx_binary_exports = {}; __export(dlx_binary_exports, { cleanDlxCache: () => cleanDlxCache, dlxBinary: () => dlxBinary, downloadBinary: () => downloadBinary, executeBinary: () => executeBinary, getDlxCachePath: () => getDlxCachePath, listDlxCache: () => listDlxCache }); module.exports = __toCommonJS(dlx_binary_exports); var import_crypto = require("crypto"); var import_os = __toESM(require("os")); var import_path = __toESM(require("path")); var import_platform = require("#constants/platform"); var import_dlx = require("./dlx"); var import_dlx_manifest = require("./dlx-manifest"); var import_http_request = require("./http-request"); var import_fs = require("./fs"); var import_objects = require("./objects"); var import_path2 = require("./path"); var import_paths = require("./paths"); var import_process_lock = require("./process-lock"); var import_spawn = require("./spawn"); let _fs; // @__NO_SIDE_EFFECTS__ function getFs() { if (_fs === void 0) { _fs = require("node:fs"); } return _fs; } function getMetadataPath(cacheEntryPath) { return import_path.default.join(cacheEntryPath, ".dlx-metadata.json"); } async function isCacheValid(cacheEntryPath, cacheTtl) { const fs = /* @__PURE__ */ getFs(); try { const metaPath = getMetadataPath(cacheEntryPath); if (!fs.existsSync(metaPath)) { return false; } const metadata = await (0, import_fs.readJson)(metaPath, { throws: false }); if (!(0, import_objects.isObjectObject)(metadata)) { return false; } const now = Date.now(); const timestamp = metadata["timestamp"]; if (typeof timestamp !== "number" || timestamp <= 0) { return false; } const age = now - timestamp; return age < cacheTtl; } catch { return false; } } async function downloadBinaryFile(url, destPath, checksum) { const cacheEntryDir = import_path.default.dirname(destPath); const lockPath = import_path.default.join(cacheEntryDir, "concurrency.lock"); return await import_process_lock.processLock.withLock( lockPath, async () => { const fs = /* @__PURE__ */ getFs(); if (fs.existsSync(destPath)) { const stats = await fs.promises.stat(destPath); if (stats.size > 0) { const fileBuffer2 = await fs.promises.readFile(destPath); const hasher2 = (0, import_crypto.createHash)("sha256"); hasher2.update(fileBuffer2); return hasher2.digest("hex"); } } try { await (0, import_http_request.httpDownload)(url, destPath); } catch (e) { throw new Error( `Failed to download binary from ${url} Destination: ${destPath} Check your internet connection or verify the URL is accessible.`, { cause: e } ); } const fileBuffer = await fs.promises.readFile(destPath); const hasher = (0, import_crypto.createHash)("sha256"); hasher.update(fileBuffer); const actualChecksum = hasher.digest("hex"); if (checksum && actualChecksum !== checksum) { await (0, import_fs.safeDelete)(destPath); throw new Error( `Checksum mismatch: expected ${checksum}, got ${actualChecksum}` ); } if (!import_platform.WIN32) { await fs.promises.chmod(destPath, 493); } return actualChecksum; }, { // Align with npm npx locking strategy. staleMs: 5e3, touchIntervalMs: 2e3 } ); } async function writeMetadata(cacheEntryPath, cacheKey, url, binaryName, checksum, size) { const metaPath = getMetadataPath(cacheEntryPath); const metadata = { version: "1.0.0", cache_key: cacheKey, timestamp: Date.now(), checksum, checksum_algorithm: "sha256", platform: import_os.default.platform(), arch: import_os.default.arch(), size, source: { type: "download", url } }; const fs = /* @__PURE__ */ getFs(); await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2)); try { const spec = `${url}:${binaryName}`; await import_dlx_manifest.dlxManifest.setBinaryEntry(spec, cacheKey, { checksum, checksum_algorithm: "sha256", platform: import_os.default.platform(), arch: import_os.default.arch(), size, source: { type: "download", url } }); } catch { } } async function cleanDlxCache(maxAge = ( /*@__INLINE__*/ require("#constants/time").DLX_BINARY_CACHE_TTL )) { const cacheDir = getDlxCachePath(); const fs = /* @__PURE__ */ getFs(); if (!fs.existsSync(cacheDir)) { return 0; } let cleaned = 0; const now = Date.now(); const entries = await fs.promises.readdir(cacheDir); for (const entry of entries) { const entryPath = import_path.default.join(cacheDir, entry); const metaPath = getMetadataPath(entryPath); try { if (!await (0, import_fs.isDir)(entryPath)) { continue; } const metadata = await (0, import_fs.readJson)(metaPath, { throws: false }); if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) { continue; } const timestamp = metadata["timestamp"]; const age = typeof timestamp === "number" && timestamp > 0 ? now - timestamp : Number.POSITIVE_INFINITY; if (age > maxAge) { await (0, import_fs.safeDelete)(entryPath, { force: true, recursive: true }); cleaned += 1; } } catch { try { const contents = await fs.promises.readdir(entryPath); if (!contents.length) { await (0, import_fs.safeDelete)(entryPath); cleaned += 1; } } catch { } } } return cleaned; } async function dlxBinary(args, options, spawnExtra) { const { cacheTtl = ( /*@__INLINE__*/ require("#constants/time").DLX_BINARY_CACHE_TTL ), checksum, force: userForce = false, name, spawnOptions, url, yes } = { __proto__: null, ...options }; const force = yes === true ? true : userForce; const cacheDir = getDlxCachePath(); const binaryName = name || `binary-${process.platform}-${import_os.default.arch()}`; const spec = `${url}:${binaryName}`; const cacheKey = (0, import_dlx.generateCacheKey)(spec); const cacheEntryDir = import_path.default.join(cacheDir, cacheKey); const binaryPath = (0, import_path2.normalizePath)(import_path.default.join(cacheEntryDir, binaryName)); const fs = /* @__PURE__ */ getFs(); let downloaded = false; let computedChecksum = checksum; if (!force && fs.existsSync(cacheEntryDir) && await isCacheValid(cacheEntryDir, cacheTtl)) { try { const metaPath = getMetadataPath(cacheEntryDir); const metadata = await (0, import_fs.readJson)(metaPath, { throws: false }); if (metadata && typeof metadata === "object" && !Array.isArray(metadata) && typeof metadata["checksum"] === "string") { computedChecksum = metadata["checksum"]; } else { downloaded = true; } } catch { downloaded = true; } } else { downloaded = true; } if (downloaded) { try { await (0, import_fs.safeMkdir)(cacheEntryDir); } catch (e) { const code = e.code; if (code === "EACCES" || code === "EPERM") { throw new Error( `Permission denied creating binary cache directory: ${cacheEntryDir} Please check directory permissions or run with appropriate access.`, { cause: e } ); } if (code === "EROFS") { throw new Error( `Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir} Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`, { cause: e } ); } throw new Error( `Failed to create binary cache directory: ${cacheEntryDir}`, { cause: e } ); } computedChecksum = await downloadBinaryFile(url, binaryPath, checksum); const stats = await fs.promises.stat(binaryPath); await writeMetadata( cacheEntryDir, cacheKey, url, binaryName, computedChecksum || "", stats.size ); } const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath); const finalSpawnOptions = needsShell ? { ...spawnOptions, env: { ...spawnOptions?.env, PATH: `${cacheEntryDir}${import_path.default.delimiter}${process.env["PATH"] || ""}` }, shell: true } : spawnOptions; const spawnPromise = (0, import_spawn.spawn)(binaryPath, args, finalSpawnOptions, spawnExtra); return { binaryPath, downloaded, spawnPromise }; } async function downloadBinary(options) { const { cacheTtl = ( /*@__INLINE__*/ require("#constants/time").DLX_BINARY_CACHE_TTL ), checksum, force = false, name, url } = { __proto__: null, ...options }; const cacheDir = getDlxCachePath(); const binaryName = name || `binary-${process.platform}-${import_os.default.arch()}`; const spec = `${url}:${binaryName}`; const cacheKey = (0, import_dlx.generateCacheKey)(spec); const cacheEntryDir = import_path.default.join(cacheDir, cacheKey); const binaryPath = (0, import_path2.normalizePath)(import_path.default.join(cacheEntryDir, binaryName)); const fs = /* @__PURE__ */ getFs(); let downloaded = false; if (!force && fs.existsSync(cacheEntryDir) && await isCacheValid(cacheEntryDir, cacheTtl)) { downloaded = false; } else { try { await (0, import_fs.safeMkdir)(cacheEntryDir); } catch (e) { const code = e.code; if (code === "EACCES" || code === "EPERM") { throw new Error( `Permission denied creating binary cache directory: ${cacheEntryDir} Please check directory permissions or run with appropriate access.`, { cause: e } ); } if (code === "EROFS") { throw new Error( `Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir} Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`, { cause: e } ); } throw new Error( `Failed to create binary cache directory: ${cacheEntryDir}`, { cause: e } ); } const computedChecksum = await downloadBinaryFile(url, binaryPath, checksum); const stats = await fs.promises.stat(binaryPath); await writeMetadata( cacheEntryDir, cacheKey, url, binaryName, computedChecksum || "", stats.size ); downloaded = true; } return { binaryPath, downloaded }; } function executeBinary(binaryPath, args, spawnOptions, spawnExtra) { const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath); const cacheEntryDir = import_path.default.dirname(binaryPath); const finalSpawnOptions = needsShell ? { ...spawnOptions, env: { ...spawnOptions?.env, PATH: `${cacheEntryDir}${import_path.default.delimiter}${process.env["PATH"] || ""}` }, shell: true } : spawnOptions; return (0, import_spawn.spawn)(binaryPath, args, finalSpawnOptions, spawnExtra); } function getDlxCachePath() { return (0, import_paths.getSocketDlxDir)(); } async function listDlxCache() { const cacheDir = getDlxCachePath(); const fs = /* @__PURE__ */ getFs(); if (!fs.existsSync(cacheDir)) { return []; } const results = []; const now = Date.now(); const entries = await fs.promises.readdir(cacheDir); for (const entry of entries) { const entryPath = import_path.default.join(cacheDir, entry); try { if (!await (0, import_fs.isDir)(entryPath)) { continue; } const metaPath = getMetadataPath(entryPath); const metadata = await (0, import_fs.readJson)(metaPath, { throws: false }); if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) { continue; } const metaObj = metadata; const source = metaObj["source"]; const url = source?.["url"] || metaObj["url"] || ""; const files = await fs.promises.readdir(entryPath); const binaryFile = files.find((f) => !f.startsWith(".")); if (binaryFile) { const binaryPath = import_path.default.join(entryPath, binaryFile); const binaryStats = await fs.promises.stat(binaryPath); results.push({ age: now - (metaObj["timestamp"] || 0), arch: metaObj["arch"] || "unknown", checksum: metaObj["checksum"] || "", name: binaryFile, platform: metaObj["platform"] || "unknown", size: binaryStats.size, url }); } } catch { } } return results; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { cleanDlxCache, dlxBinary, downloadBinary, executeBinary, getDlxCachePath, listDlxCache });