2015-11-05 25 views
6

Potrzebuję użyć wbudowanego modułu node.js 'crypto' z mojego dodatku C++. Próbowałem znaleźć przykłady dodatków C++, które korzystają z wbudowanych modułów, ale nie powiodło się. Sprawdziłem w node_crypto.h/.cc i ma ona różne sygnatury funkcji w porównaniu z dokumentacją crypto node.js, chronionymi konstruktorami itp. Node_crypto.h zawiera deklarację InitCrypto() z jednym parametrem, ale node_crypto.cc nie ma definicji taka funkcja. Istnieje tylko InitCrypto z czterema parametrami. Próbowałem mimo wszystko używać InitCrypto z jednym parametrem i otrzymałem "błąd wyszukiwania symbolu".Jak korzystać z wbudowanych modułów node.js z dodatków C++

Mogę przekazać wynik wymagania ('crypto') do mojego dodatku, a następnie pracować z tym obiektem, ale jest to tak niezabezpieczone. Nasz kod JS działa na serwerze klienta.

Na razie myślę, że jest prostsze dla addonu C++, aby użyć czegoś takiego jak openssl lib zamiast wbudowanego modułu "crypto".

Potrzebuję więc działającego przykładu z dodatkiem C++, który używa modułu "crypto" lub linku do artykułu na ten temat.

Przydałby się przykład użycia dowolnego wbudowanego modułu z dodatku C++.

Odpowiedz

6

Użyłem tego samego sposobu, gdy miałem potrzebę szyfrowania/odszyfrowywania danych w addonie Nodejs.

Jak rozumiem, klasy od node_crypto.h są używane do tworzenia natywnych powiązań w Nodejs, nie mogłem ich użyć w moim dodatku.

Potem próbowałem użyć OpenSSL z Nodejs, ale nie mogłem tego zrobić, ponieważ OpenSSL jest statycznie połączony z plikiem wykonywalnym Nodejs.

Potem próbowałem wezwać kod JavaScript z C++ i wreszcie następujące rozwiązanie - wywoływać funkcje Nodejs z kodu C++:

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 
} 

Jak widać, C++ kod z V8 API jest dość rozwlekły . W prawdziwym projekcie użyłem funkcji narzędzi z mojej biblioteki v8pp, aby uzyskać właściwości obiektu i funkcje wywołania z konwersją danych do uchwytów V8.

+0

Wielkie dzięki! To rozwiązanie jest bezpieczniejsze niż przekazanie wyniku require ('crypto') do addon. Jeśli nikt nie będzie publikował czystego rozwiązania C++ do końca listopada, zaznaczę to jako odpowiedź. Czy poprawnie rozumiem, że ktoś może poprawić wbudowane moduły w plikach node_src_root/lib/* .js, a te poprawione pliki * .js będą używane przez dodatek? Czy wykonałeś jakieś testy wydajności? Powiedz, spróbuj cachować niektóre funkcje w obiektach globalnych i porównywać je z bibliotekami kryptograficznymi innych firm? – Dzenly

+1

Użyłem tego jako szybki i brudny sposób, aby uniknąć zależności od zewnętrznej biblioteki kryptograficznej w moim dodatku, ponieważ budowanie takich rzeczy jak OpenSSL byłoby bólem głowy. Tak, masz rację, to rozwiązanie użyło 'lib \ *. Js' ze źródeł węzłów. Jeśli ktoś zmieniłby źródła i uruchomił zmodyfikowany Nodejs, może to być niezabezpieczone. Potrzebowałem do szyfrowania/odszyfrowania bloku danych tylko raz przy starcie aplikacji. Tak więc nie wykonałem żadnych testów wydajności tego rozwiązania. – pmed

+0

Świetne rozwiązanie! – Icebob