【问题标题】:How to lie to program about `process.platform`?如何对“process.platform”撒谎?
【发布时间】:2019-01-26 10:11:45
【问题描述】:

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

有什么方法可以欺骗这个 CLI 并模拟它正在运行,例如Linux 还是 macOS?

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

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


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

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

【问题讨论】:

  • 案例是特定于一个包的。请指定包名。
  • 这不是真的,但我创建了 github.com/janpio/nodejs-cli-nowin npmjs.com/package/nodejs-cli-nowin 重新创建了测试行为。通过npm i -g nodejs-cli-nowin安装。
  • 它没有澄清问题,因为它取决于包内部。我提供了一个一般性的答案。不看包是如何工作的,就不可能说它是否适用。
  • 看了你的回答我明白了。我现在正在查看的包是weex-toolkitnpm i -g weex-toolkitweex create weexweex platform add iosweex run iosweex build ios 然后执行条件。带有process.platform 的代码是here,但老实说我还不明白weex-toolkit 是如何调用它的。插件以某种方式加载:/
  • 那么是 weex-toolkit 还是 weex-pack?它们似乎是不同的包。我查了一下,它有一堆依赖,你可以确定错误的 process.platform 会搞砸很多平台相关的东西。您可以做的最好的事情是在特定模块中模拟process,即修改module wrapper以添加本地流程变量var process = isModuleWherePlatformIsMocked ? Object.create(global.process, { platform: { value: 'linux' } }) : global.process

标签: node.js command-line-interface


【解决方案1】:

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

wrapper-package/index.js

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

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

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

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

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

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');

【讨论】:

  • 具有讽刺意味的是,生成子进程不起作用,因为节点尝试为其使用 bin/shchild_process.js:651 throw err; ^ Error: spawnSync /bin/sh ENOENT ;)
  • 有道理。模拟 process.platform 将破坏 Node 中具有动态平台相关代码的所有内容。
  • 但一般来说你的代码是有效的!也许有办法只在特定模块/方法/调用之前应用它?
  • 我发布了一个示例,如何修改模块包装器以更改特定模块中的 process.platform。我不能说这是否可以轻松应用于您的案例。这样的补丁是脆弱的,我建议尽可能避免这种情况。
  • 很高兴它有帮助。是的,检测来电者更加棘手,但您也可以使用 npmjs.com/package/caller-id 来做到这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-23
  • 1970-01-01
  • 1970-01-01
  • 2012-03-23
  • 1970-01-01
  • 1970-01-01
  • 2014-03-01
相关资源
最近更新 更多