如何从C++插件中使用node.js内置模块

8
我需要从我的C++插件中使用node.js内置模块'crypto'。我尝试找到使用内置模块的C++插件示例,但失败了。我查看了node_crypto.h/.cc文件,发现它与node.js加密文档具有不同的函数签名、受保护的构造函数等等。node_crypto.h包含一个带有一个参数的InitCrypto()声明,但是node_crypto.cc没有这样的函数定义。只有带有四个参数的InitCrypto。我尝试使用带有一个参数的InitCrypto,但得到了“符号查找错误”。
我可以将require('crypto')的结果传递给我的插件,然后使用此对象进行操作,但这很不安全。我们的JS代码在客户服务器上运行。
目前,我认为对于C++插件来说,使用类似openssl库而不是内置的node模块'crypto'更简单。
因此,我需要一个使用'crypto'模块的C++插件的工作示例或链接到一些相关文章。任何使用任何内置模块的C++插件示例都将有所帮助。
1个回答

9

当我需要在Nodejs插件中加密/解密数据时,我使用了相同的方法。

据我所知,node_crypto.h中的类用于在Nodejs中进行本地绑定,但我无法在我的插件中使用它们。

然后我尝试从Nodejs中使用OpenSSL,但由于OpenSSL静态链接到Nodejs可执行文件中,因此无法实现。

之后,我尝试从C++调用JavaScript代码,最终得到了以下解决方案 - 从C++代码中调用Nodejs函数:

using namespace v8;

// persistent handle for the crypto module
static Persistent<Object> node_crypto;

// Addon startup procedure
void Init(Local<Object> exports, Local<Object> module)
{
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    // get `require` function
    Local<Function> require = module->Get(String::NewFromUtf8(isolate, "require")).As<Function>();

    // call require('crypto')
    Local<Value> args[] = { String::NewFromUtf8(isolate, "crypto") };
    Local<Object> crypto = require->Call(module, 1, args).As<Object>();

    // store crypto module in persistent handle for further use
    node_crypto.Reset(isolate, crypto);   
}

NODE_MODULE(addon, Init);

// must be invoked in then Node main thread since the function uses V8 API
std::string encrypt(std::string const& key, std::string const& text)
{
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);

    // get local handle from persistent
    Local<Object> crypto = Local<Object>::New(isolate, node_crypto);

    // get `createCipher` function from the crypto module
    Local<Function> createCipher = crypto->Get(String::NewFromUtf8(isolate, "createCipher")).As<Function>();

    // call crypto.createCipher("aes256", key)
    Local<Value> create_args[] =
    {
        String::NewFromUtf8(isolate, "aes256"),
        String::NewFromUtf8(isolate, key.c_str())
    };
    Local<Object> cipher = createCipher->Call(crypto, 2, create_args).As<Object>();

    // get update and final functions from the crypto module
    Local<Function> update = cipher->Get(String::NewFromUtf8(isolate, "update")).As<Function>();
    Local<Function> final = cipher->Get(String::NewFromUtf8(isolate, "final")).As<Function>();

    // buf1 = cipher.update(text), buf2 = cipher.final()
    Local<Value> update_args[] = { node::Buffer::New(isolate, text.data(), text.size()) };

    Local<Value> buf1 = update->Call(cipher, 1, update_args);
    Local<Value> buf2 = final->Call(cipher, 0, nullptr);

    // concatenate update and final buffers into result string
    char const* const data1 = node::Buffer::Data(buf1);
    char const* const data2 = node::Buffer::Data(buf2);

    size_t const size1 = node::Buffer::Length(buf1);
    size_t const size2 = node::Buffer::Lenght(buf2);

    std::string result;
    result.reserve(size1 + size2);
    result.append(data1, size1);
    result.append(data2, size2);
    return result;
}

std::string decrypt(std::string const& key, std::string const& text)
{
    // similar as in encrypt, use createDecipher instead
}

正如您所见,使用V8 API的C++代码相当冗长。在实际项目中,我使用了我的v8pp库中的实用函数来获取对象属性,并带有数据转换到V8句柄的调用函数。


非常感谢!这个解决方案比传递 require('crypto') 的结果到插件更安全。如果在11月底之前没有人发布纯C ++的解决方案,我将把这个标记为答案。我是否正确理解,有人可以在node_src_root / lib / * .js文件中更正内置模块,然后插件将使用这些更正的* .js文件?您做过任何性能测试吗?例如,尝试将一些函数缓存到全局对象中,并与第三方加密库进行比较? - Dzenly
1
我使用这种快速而不太规范的方法来避免我的插件依赖外部加密库,因为构建像 OpenSSL 这样的东西会很麻烦。是的,你说得对,这个解决方案使用了来自 Node 源代码的 lib\*.js。如果有人改变了源代码并运行了这个修改过的 Nodejs,它可能是不安全的。我只需要在应用程序启动时加密/解密一块数据一次。所以我没有对这个解决方案进行任何性能测试。 - pmed
很棒的解决方案! - Icebob
2
谢谢!顺便说一下,自从6.4.0版本(在拉取请求https://github.com/nodejs/node/pull/7983中)起,Nodejs在Windows上导出OpenSSL符号。因此,node-gyp wiki(https://github.com/nodejs/node-gyp/wiki/Linking-to-OpenSSL)中的方法也可能适用。 - pmed
不幸的是,Node API(以前的n-api)不再提供“module”访问权限,需要从js中传递:https://github.com/nodejs/node-addon-api/issues/449 - Dickeylth
据我所知,对于上下文感知插件,仍然存在NODE_MODULE_INIT宏,允许本地C++插件访问exportsmodulecontext。Node API是Node.js C++插件API的C语言抽象层,因此它可以放弃一些东西,以更抽象的方式呈现。 - pmed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接