UNPKG

brave-real-playwright-core

Version:

Brave-optimized Playwright Core (v1.55.0) with comprehensive stealth patches and error stack sanitization

372 lines (370 loc) 15.9 kB
"use strict"; 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 dependencies_exports = {}; __export(dependencies_exports, { dockerVersion: () => dockerVersion, installDependenciesLinux: () => installDependenciesLinux, installDependenciesWindows: () => installDependenciesWindows, readDockerVersionSync: () => readDockerVersionSync, transformCommandsForRoot: () => transformCommandsForRoot, validateDependenciesLinux: () => validateDependenciesLinux, validateDependenciesWindows: () => validateDependenciesWindows, writeDockerVersion: () => writeDockerVersion }); module.exports = __toCommonJS(dependencies_exports); var childProcess = __toESM(require("child_process")); var import_fs = __toESM(require("fs")); var import_os = __toESM(require("os")); var import_path = __toESM(require("path")); var import_nativeDeps = require("./nativeDeps"); var import_ascii = require("../utils/ascii"); var import_hostPlatform = require("../utils/hostPlatform"); var import_spawnAsync = require("../utils/spawnAsync"); var import_userAgent = require("../utils/userAgent"); var import__ = require("."); const BIN_DIRECTORY = import_path.default.join(__dirname, "..", "..", "..", "bin"); const languageBindingVersion = process.env.PW_CLI_DISPLAY_VERSION || require("../../../package.json").version; const dockerVersionFilePath = "/ms-playwright/.docker-info"; async function writeDockerVersion(dockerImageNameTemplate) { await import_fs.default.promises.mkdir(import_path.default.dirname(dockerVersionFilePath), { recursive: true }); await import_fs.default.promises.writeFile(dockerVersionFilePath, JSON.stringify(dockerVersion(dockerImageNameTemplate), null, 2), "utf8"); await import_fs.default.promises.chmod(dockerVersionFilePath, 511); } function dockerVersion(dockerImageNameTemplate) { return { driverVersion: languageBindingVersion, dockerImageName: dockerImageNameTemplate.replace("%version%", languageBindingVersion) }; } function readDockerVersionSync() { try { const data = JSON.parse(import_fs.default.readFileSync(dockerVersionFilePath, "utf8")); return { ...data, dockerImageNameTemplate: data.dockerImageName.replace(data.driverVersion, "%version%") }; } catch (e) { return null; } } const checkExecutable = (filePath) => { if (process.platform === "win32") return filePath.endsWith(".exe"); return import_fs.default.promises.access(filePath, import_fs.default.constants.X_OK).then(() => true).catch(() => false); }; function isSupportedWindowsVersion() { if (import_os.default.platform() !== "win32" || import_os.default.arch() !== "x64") return false; const [major, minor] = import_os.default.release().split(".").map((token) => parseInt(token, 10)); return major > 6 || major === 6 && minor > 1; } async function installDependenciesWindows(targets, dryRun) { if (targets.has("chromium")) { const command = "powershell.exe"; const args = ["-ExecutionPolicy", "Bypass", "-File", import_path.default.join(BIN_DIRECTORY, "install_media_pack.ps1")]; if (dryRun) { console.log(`${command} ${quoteProcessArgs(args).join(" ")}`); return; } const { code } = await (0, import_spawnAsync.spawnAsync)(command, args, { cwd: BIN_DIRECTORY, stdio: "inherit" }); if (code !== 0) throw new Error("Failed to install windows dependencies!"); } } async function installDependenciesLinux(targets, dryRun) { const libraries = []; const platform = import_hostPlatform.hostPlatform; if (!import_hostPlatform.isOfficiallySupportedPlatform) console.warn(`BEWARE: your OS is not officially supported by Playwright; installing dependencies for ${platform} as a fallback.`); for (const target of targets) { const info = import_nativeDeps.deps[platform]; if (!info) { console.warn(`Cannot install dependencies for ${platform} with Playwright ${(0, import_userAgent.getPlaywrightVersion)()}!`); return; } libraries.push(...info[target]); } const uniqueLibraries = Array.from(new Set(libraries)); if (!dryRun) console.log(`Installing dependencies...`); const commands = []; commands.push("apt-get update"); commands.push([ "apt-get", "install", "-y", "--no-install-recommends", ...uniqueLibraries ].join(" ")); const { command, args, elevatedPermissions } = await transformCommandsForRoot(commands); if (dryRun) { console.log(`${command} ${quoteProcessArgs(args).join(" ")}`); return; } if (elevatedPermissions) console.log("Switching to root user to install dependencies..."); const child = childProcess.spawn(command, args, { stdio: "inherit" }); await new Promise((resolve, reject) => { child.on("exit", (code) => code === 0 ? resolve() : reject(new Error(`Installation process exited with code: ${code}`))); child.on("error", reject); }); } async function validateDependenciesWindows(sdkLanguage, windowsExeAndDllDirectories) { const directoryPaths = windowsExeAndDllDirectories; const lddPaths = []; for (const directoryPath of directoryPaths) lddPaths.push(...await executablesOrSharedLibraries(directoryPath)); const allMissingDeps = await Promise.all(lddPaths.map((lddPath) => missingFileDependenciesWindows(sdkLanguage, lddPath))); const missingDeps = /* @__PURE__ */ new Set(); for (const deps2 of allMissingDeps) { for (const dep of deps2) missingDeps.add(dep); } if (!missingDeps.size) return; let isCrtMissing = false; let isMediaFoundationMissing = false; for (const dep of missingDeps) { if (dep.startsWith("api-ms-win-crt") || dep === "vcruntime140.dll" || dep === "vcruntime140_1.dll" || dep === "msvcp140.dll") isCrtMissing = true; else if (dep === "mf.dll" || dep === "mfplat.dll" || dep === "msmpeg2vdec.dll" || dep === "evr.dll" || dep === "avrt.dll") isMediaFoundationMissing = true; } const details = []; if (isCrtMissing) { details.push( `Some of the Universal C Runtime files cannot be found on the system. You can fix`, `that by installing Microsoft Visual C++ Redistributable for Visual Studio from:`, `https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads`, `` ); } if (isMediaFoundationMissing) { details.push( `Some of the Media Foundation files cannot be found on the system. If you are`, `on Windows Server try fixing this by running the following command in PowerShell`, `as Administrator:`, ``, ` Install-WindowsFeature Server-Media-Foundation`, ``, `For Windows N editions visit:`, `https://support.microsoft.com/en-us/help/3145500/media-feature-pack-list-for-windows-n-editions`, `` ); } details.push( `Full list of missing libraries:`, ` ${[...missingDeps].join("\n ")}`, `` ); const message = `Host system is missing dependencies! ${details.join("\n")}`; if (isSupportedWindowsVersion()) { throw new Error(message); } else { console.warn(`WARNING: running on unsupported windows version!`); console.warn(message); } } async function validateDependenciesLinux(sdkLanguage, linuxLddDirectories, dlOpenLibraries) { const directoryPaths = linuxLddDirectories; const lddPaths = []; for (const directoryPath of directoryPaths) lddPaths.push(...await executablesOrSharedLibraries(directoryPath)); const missingDepsPerFile = await Promise.all(lddPaths.map((lddPath) => missingFileDependencies(lddPath, directoryPaths))); const missingDeps = /* @__PURE__ */ new Set(); for (const deps2 of missingDepsPerFile) { for (const dep of deps2) missingDeps.add(dep); } for (const dep of await missingDLOPENLibraries(dlOpenLibraries)) missingDeps.add(dep); if (!missingDeps.size) return; const allMissingDeps = new Set(missingDeps); const missingPackages = /* @__PURE__ */ new Set(); const libraryToPackageNameMapping = import_nativeDeps.deps[import_hostPlatform.hostPlatform] ? { ...import_nativeDeps.deps[import_hostPlatform.hostPlatform]?.lib2package || {}, ...MANUAL_LIBRARY_TO_PACKAGE_NAME_UBUNTU } : {}; for (const missingDep of missingDeps) { const packageName = libraryToPackageNameMapping[missingDep]; if (packageName) { missingPackages.add(packageName); missingDeps.delete(missingDep); } } const maybeSudo = process.getuid?.() && import_os.default.platform() !== "win32" ? "sudo " : ""; const dockerInfo = readDockerVersionSync(); const errorLines = [ `Host system is missing dependencies to run browsers.` ]; if (dockerInfo && !dockerInfo.driverVersion.startsWith((0, import_userAgent.getPlaywrightVersion)( true /* majorMinorOnly */ ) + ".")) { const pwVersion = (0, import_userAgent.getPlaywrightVersion)(); const requiredDockerImage = dockerInfo.dockerImageName.replace(dockerInfo.driverVersion, pwVersion); errorLines.push(...[ `This is most likely due to Docker image version not matching Playwright version:`, `- Playwright : ${pwVersion}`, `- Docker image: ${dockerInfo.driverVersion}`, ``, `Either:`, `- (recommended) use Docker image "${requiredDockerImage}"`, `- (alternative 1) run the following command inside Docker to install missing dependencies:`, ``, ` ${maybeSudo}${(0, import__.buildPlaywrightCLICommand)(sdkLanguage, "install-deps")}`, ``, `- (alternative 2) use apt inside Docker:`, ``, ` ${maybeSudo}apt-get install ${[...missingPackages].join("\\\n ")}`, ``, `<3 Playwright Team` ]); } else if (missingPackages.size && !missingDeps.size) { errorLines.push(...[ `Please install them with the following command:`, ``, ` ${maybeSudo}${(0, import__.buildPlaywrightCLICommand)(sdkLanguage, "install-deps")}`, ``, `Alternatively, use apt:`, ` ${maybeSudo}apt-get install ${[...missingPackages].join("\\\n ")}`, ``, `<3 Playwright Team` ]); } else { errorLines.push(...[ `Missing libraries:`, ...[...allMissingDeps].map((dep) => " " + dep) ]); } throw new Error("\n" + (0, import_ascii.wrapInASCIIBox)(errorLines.join("\n"), 1)); } function isSharedLib(basename) { switch (import_os.default.platform()) { case "linux": return basename.endsWith(".so") || basename.includes(".so."); case "win32": return basename.endsWith(".dll"); default: return false; } } async function executablesOrSharedLibraries(directoryPath) { if (!import_fs.default.existsSync(directoryPath)) return []; const allPaths = (await import_fs.default.promises.readdir(directoryPath)).map((file) => import_path.default.resolve(directoryPath, file)); const allStats = await Promise.all(allPaths.map((aPath) => import_fs.default.promises.stat(aPath))); const filePaths = allPaths.filter((aPath, index) => allStats[index].isFile()); const executablersOrLibraries = (await Promise.all(filePaths.map(async (filePath) => { const basename = import_path.default.basename(filePath).toLowerCase(); if (isSharedLib(basename)) return filePath; if (await checkExecutable(filePath)) return filePath; return false; }))).filter(Boolean); return executablersOrLibraries; } async function missingFileDependenciesWindows(sdkLanguage, filePath) { const executable = import__.registry.findExecutable("winldd").executablePathOrDie(sdkLanguage); const dirname = import_path.default.dirname(filePath); const { stdout, code } = await (0, import_spawnAsync.spawnAsync)(executable, [filePath], { cwd: dirname, env: { ...process.env, LD_LIBRARY_PATH: process.env.LD_LIBRARY_PATH ? `${process.env.LD_LIBRARY_PATH}:${dirname}` : dirname } }); if (code !== 0) return []; const missingDeps = stdout.split("\n").map((line) => line.trim()).filter((line) => line.endsWith("not found") && line.includes("=>")).map((line) => line.split("=>")[0].trim().toLowerCase()); return missingDeps; } async function missingFileDependencies(filePath, extraLDPaths) { const dirname = import_path.default.dirname(filePath); let LD_LIBRARY_PATH = extraLDPaths.join(":"); if (process.env.LD_LIBRARY_PATH) LD_LIBRARY_PATH = `${process.env.LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}`; const { stdout, code } = await (0, import_spawnAsync.spawnAsync)("ldd", [filePath], { cwd: dirname, env: { ...process.env, LD_LIBRARY_PATH } }); if (code !== 0) return []; const missingDeps = stdout.split("\n").map((line) => line.trim()).filter((line) => line.endsWith("not found") && line.includes("=>")).map((line) => line.split("=>")[0].trim()); return missingDeps; } async function missingDLOPENLibraries(libraries) { if (!libraries.length) return []; const { stdout, code, error } = await (0, import_spawnAsync.spawnAsync)("/sbin/ldconfig", ["-p"], {}); if (code !== 0 || error) return []; const isLibraryAvailable = (library) => stdout.toLowerCase().includes(library.toLowerCase()); return libraries.filter((library) => !isLibraryAvailable(library)); } const MANUAL_LIBRARY_TO_PACKAGE_NAME_UBUNTU = { // libgstlibav.so (the only actual library provided by gstreamer1.0-libav) is not // in the ldconfig cache, so we detect the actual library required for playing h.264 // and if it's missing recommend installing missing gstreamer lib. // gstreamer1.0-libav -> libavcodec57 -> libx264-152 "libx264.so": "gstreamer1.0-libav" }; function quoteProcessArgs(args) { return args.map((arg) => { if (arg.includes(" ")) return `"${arg}"`; return arg; }); } async function transformCommandsForRoot(commands) { const isRoot = process.getuid?.() === 0; if (isRoot) return { command: "sh", args: ["-c", `${commands.join("&& ")}`], elevatedPermissions: false }; const sudoExists = await (0, import_spawnAsync.spawnAsync)("which", ["sudo"]); if (sudoExists.code === 0) return { command: "sudo", args: ["--", "sh", "-c", `${commands.join("&& ")}`], elevatedPermissions: true }; return { command: "su", args: ["root", "-c", `${commands.join("&& ")}`], elevatedPermissions: true }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { dockerVersion, installDependenciesLinux, installDependenciesWindows, readDockerVersionSync, transformCommandsForRoot, validateDependenciesLinux, validateDependenciesWindows, writeDockerVersion });