首页 > 解决方案 > 如何对“process.platform”撒谎?

问题描述

有一个在 Node 上运行的 CLI,可以通过command命令行执行。在其代码中,Windows 用户禁用了某些功能if (process.platform === 'win32') { process.exit(1); }。现在我想禁用此检查,并允许 Windows 用户使用“隐藏”功能(通常所需的软件没有安装在 Windows 上,但我有一个特殊的设置)。

有什么方法可以欺骗这个 CLI 并模拟它在例如 Linux 或 macOS 上运行吗?

当然,我可以分叉 CLI,删除检查并使用我自己的版本 - 但这需要为每个版本重复此过程。由于此功能也应该可供其他用户使用,我将不得不发布分叉和修改后的 CLI,这可能是其用户经常混淆的原因(版本号呢?我使用相同的command吗?) - 99.9%代码将保持不变。

我是否可以编写自己的 CLI,做一些“伪造”环境的操作,然后执行已安装的原始 CLI,然后进行清理?


我创建了一个与 CLI 相同的示例包,但只执行我正在调查的部分:

通过安装npm i -g nodejs-cli-nowin

标签: node.jscommand-line-interface

解决方案


基本上,应该使用 wrapper 包而不是原始包来提供入口点。process.platform应该在原始包运行之前用新值模拟。

包装器包/index.js

Object.defineProperty(process, 'platform', { value: 'linux' });

require('original-package/bin/entry-point.js');

如果原始包生成子进程,这不会影响子进程。

这并不能保证该包将按预期在模拟平台上工作,很有可能它不会。即使包本身工作正常,这也可能导致依赖于process.platform.

为了process.platform只影响特定模块,platform全局应该被局部变量遮蔽。为此,应修改模块包装函数:

const Module = require('module')

const escapedPatchedModulePath = require.resolve('original-package/module-to-patch.js')
  .replace(/\\/g, '\\\\');

Module.wrapper[0] += `
const isPatchedModule = __filename === "${escapedPatchedModulePath}";
let process = isPatchedModule
  ? Object.create(global.process, { platform: { value: 'linux' } })
  : global.process;
`;

require('original-package/bin/entry-point.js');

推荐阅读