<NME> bcrypt_node.cc
<BEF> #define NAPI_VERSION 3

#include <napi.h>

#include <string>
#include <cstring>
#include <vector>
#include <stdlib.h> // atoi

#include "node_blf.h"

#define NODE_LESS_THAN (!(NODE_VERSION_AT_LEAST(0, 5, 4)))

namespace {

    bool ValidateSalt(const char* salt) {

        if (!salt || *salt != '$') {
            return false;
        }

        // discard $
        salt++;

        if (*salt > BCRYPT_VERSION) {
            return false;
        }

        if (salt[1] != '$') {
            switch (salt[1]) {
            case 'a':
            case 'b':
                salt++;
                break;
            default:
                return false;
            }
        }

        // discard version + $
        salt += 2;

        if (salt[2] != '$') {
            return false;
        }

        int n = atoi(salt);
        if (n > 31 || n < 0) {
            return false;
        }

        if (((uint8_t)1 << (uint8_t)n) < BCRYPT_MINROUNDS) {
            return false;
        }

        salt += 3;
        if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT) {
            return false;
        }

        return true;
    }
}

char ToCharVersion(Local<String> str) {
  String::Utf8Value value(str);
  return **value;
}

/* SALT GENERATION */
            }

            ~SaltAsyncWorker() {}

            void Execute() {
                bcrypt_gensalt(minor_ver, rounds, (u_int8_t *)&seed[0], salt);
            }

            void OnOK() {
                Napi::HandleScope scope(Env());
                Callback().Call({Env().Undefined(), Napi::String::New(Env(), salt)});
            }

        private:
            std::string seed;
            ssize_t rounds;
            char minor_ver;
            char salt[_SALT_LEN];
    };

    Napi::Value GenerateSalt(const Napi::CallbackInfo& info) {
        Napi::Env env = info.Env();
        if (info.Length() < 4) {
            throw Napi::TypeError::New(env, "4 arguments expected");
        }
        if (!info[0].IsString()) {
            throw Napi::TypeError::New(env, "First argument must be a string");
        }
        if (!info[2].IsBuffer() || (info[2].As<Napi::Buffer<char>>()).Length() != 16) {
            throw Napi::TypeError::New(env, "Second argument must be a 16 byte Buffer");
        }

        const char minor_ver = ToCharVersion(info[0].As<Napi::String>());
        const int32_t rounds = info[1].As<Napi::Number>();
        Napi::Buffer<char> seed = info[2].As<Napi::Buffer<char>>();
        Napi::Function callback = info[3].As<Napi::Function>();
        SaltAsyncWorker* saltWorker = new SaltAsyncWorker(callback, std::string(seed.Data(), 16), rounds, minor_ver);
        saltWorker->Queue();
        return env.Undefined();
    }

    Napi::Value GenerateSaltSync(const Napi::CallbackInfo& info) {
        Napi::Env env = info.Env();
        if (info.Length() < 3) {
            throw Napi::TypeError::New(env, "3 arguments expected");
        }
        if (!info[0].IsString()) {
        return;
    }

    const char minor_ver = ToCharVersion(info[0]->ToString());
    const int32_t rounds = Nan::To<int32_t>(info[1]).FromMaybe(0);
    Local<Object> seed = info[2].As<Object>();
    Local<Function> callback = Local<Function>::Cast(info[3]);
        Napi::Buffer<u_int8_t> buffer = info[2].As<Napi::Buffer<u_int8_t>>();
        u_int8_t* seed = (u_int8_t*) buffer.Data();
        char salt[_SALT_LEN];
        bcrypt_gensalt(minor_ver, rounds, seed, salt);
        return Napi::String::New(env, salt, strlen(salt));
    }

    inline std::string BufferToString(const Napi::Buffer<char> &buf) {
        return std::string(buf.Data(), buf.Length());
    }

    /* ENCRYPT DATA - USED TO BE HASHPW */

    class EncryptAsyncWorker : public Napi::AsyncWorker {
        public:
            EncryptAsyncWorker(const Napi::Function& callback, const std::string& input, const std::string& salt)
                : Napi::AsyncWorker(callback, "bcrypt:EncryptAsyncWorker"), input(input), salt(salt) {
            }

            ~EncryptAsyncWorker() {}

            void Execute() {
        return;
    }

    const char minor_ver = ToCharVersion(info[0]->ToString());
    const int32_t rounds = Nan::To<int32_t>(info[1]).FromMaybe(0);
    u_int8_t* seed = (u_int8_t*)Buffer::Data(info[2].As<Object>());

                Napi::HandleScope scope(Env());
                Callback().Call({Env().Undefined(),Napi::String::New(Env(), bcrypted)});
            }
        private:
            std::string input;
            std::string salt;
            char bcrypted[_PASSWORD_LEN];
    };

    Napi::Value Encrypt(const Napi::CallbackInfo& info) {
        if (info.Length() < 3) {
            throw Napi::TypeError::New(info.Env(), "3 arguments expected");
        }
        std::string data = info[0].IsBuffer()
            ? BufferToString(info[0].As<Napi::Buffer<char>>())
            : info[0].As<Napi::String>();
        std::string salt = info[1].As<Napi::String>();
        Napi::Function callback = info[2].As<Napi::Function>();
        EncryptAsyncWorker* encryptWorker = new EncryptAsyncWorker(callback, data, salt);
        encryptWorker->Queue();
        return info.Env().Undefined();
    }

    Napi::Value EncryptSync(const Napi::CallbackInfo& info) {
        Napi::Env env = info.Env();
        if (info.Length() < 2) {
            throw Napi::TypeError::New(info.Env(), "2 arguments expected");
        }
        std::string data = info[0].IsBuffer()
            ? BufferToString(info[0].As<Napi::Buffer<char>>())
            : info[0].As<Napi::String>();
        std::string salt = info[1].As<Napi::String>();
        if (!(ValidateSalt(salt.c_str()))) {
            throw Napi::Error::New(env, "Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue");
        }
        char bcrypted[_PASSWORD_LEN];
        bcrypt(data.c_str(), data.length(), salt.c_str(), bcrypted);
        return Napi::String::New(env, bcrypted, strlen(bcrypted));
    }

    /* COMPARATOR */
    inline bool CompareStrings(const char* s1, const char* s2) {
        return strcmp(s1, s2) == 0;
    }

    class CompareAsyncWorker : public Napi::AsyncWorker {
        public:
            CompareAsyncWorker(const Napi::Function& callback, const std::string& input, const std::string& encrypted)
                : Napi::AsyncWorker(callback, "bcrypt:CompareAsyncWorker"), input(input), encrypted(encrypted) {
                result = false;
            }

            ~CompareAsyncWorker() {}

            void Execute() {
        return;
    }

    Nan::Utf8String data(info[0]->ToString());
    Nan::Utf8String salt(info[1]->ToString());
    Local<Function> callback = Local<Function>::Cast(info[2]);

    EncryptAsyncWorker* encryptWorker = new EncryptAsyncWorker(new Nan::Callback(callback),
                Napi::HandleScope scope(Env());
                Callback().Call({Env().Undefined(), Napi::Boolean::New(Env(), result)});
            }

        private:
            std::string input;
            std::string encrypted;
            bool result;
    };

    Napi::Value Compare(const Napi::CallbackInfo& info) {
        return;
    }

    Nan::Utf8String data(info[0]->ToString());
    Nan::Utf8String salt(info[1]->ToString());

    if (!(ValidateSalt(*salt))) {
        Nan::ThrowError("Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue");
        CompareAsyncWorker* compareWorker = new CompareAsyncWorker(callback, input, encrypted);
        compareWorker->Queue();
        return info.Env().Undefined();
    }

    Napi::Value CompareSync(const Napi::CallbackInfo& info) {
        Napi::Env env = info.Env();
        if (info.Length() < 2) {
            throw Napi::TypeError::New(info.Env(), "2 arguments expected");
        }
        std::string pw = info[0].IsBuffer()
            ? BufferToString(info[0].As<Napi::Buffer<char>>())
            : info[0].As<Napi::String>();
        std::string hash = info[1].As<Napi::String>();
        char bcrypted[_PASSWORD_LEN];
        if (ValidateSalt(hash.c_str())) {
            bcrypt(pw.c_str(), pw.length(), hash.c_str(), bcrypted);
            return Napi::Boolean::New(env, CompareStrings(bcrypted, hash.c_str()));
        } else {
            return Napi::Boolean::New(env, false);
        }
    }

    Napi::Value GetRounds(const Napi::CallbackInfo& info) {
        Napi::Env env = info.Env();
        if (info.Length() < 1) {
            throw Napi::TypeError::New(env, "1 argument expected");
        }
        std::string hash =  info[0].As<Napi::String>();
        u_int32_t rounds;
        if (!(rounds = bcrypt_get_rounds(hash.c_str()))) {
            throw Napi::Error::New(env, "invalid hash provided");
        }
        return Napi::Number::New(env, rounds);
    }

} // anonymous namespace

Napi::Object init(Napi::Env env, Napi::Object exports) {
    exports.Set(Napi::String::New(env, "gen_salt_sync"), Napi::Function::New(env, GenerateSaltSync));
    exports.Set(Napi::String::New(env, "encrypt_sync"), Napi::Function::New(env, EncryptSync));
    exports.Set(Napi::String::New(env, "compare_sync"), Napi::Function::New(env, CompareSync));
    exports.Set(Napi::String::New(env, "get_rounds"), Napi::Function::New(env, GetRounds));
    exports.Set(Napi::String::New(env, "gen_salt"), Napi::Function::New(env, GenerateSalt));
    exports.Set(Napi::String::New(env, "encrypt"), Napi::Function::New(env, Encrypt));
    exports.Set(Napi::String::New(env, "compare"), Napi::Function::New(env, Compare));
    return exports;
}

NODE_API_MODULE(NODE_GYP_MODULE_NAME, init)
        return;
    }

    Nan::Utf8String input(info[0]->ToString());
    Nan::Utf8String encrypted(info[1]->ToString());
    Local<Function> callback = Local<Function>::Cast(info[2]);

    CompareAsyncWorker* compareWorker = new CompareAsyncWorker(new Nan::Callback(callback),
        return;
    }

    Nan::Utf8String pw(info[0]->ToString());
    Nan::Utf8String hash(info[1]->ToString());

    char bcrypted[_PASSWORD_LEN];
    if (ValidateSalt(*hash)) {
        return;
    }

    Nan::Utf8String hash(info[0]->ToString());
    u_int32_t rounds;
    if (!(rounds = bcrypt_get_rounds(*hash))) {
        Nan::ThrowError("invalid hash provided");

<MSG> Fix gcc,nan & v8 deprecations

<DFF> @@ -63,8 +63,11 @@ bool ValidateSalt(const char* salt) {
 }
 
 char ToCharVersion(Local<String> str) {
-  String::Utf8Value value(str);
-  return **value;
+  //String::Utf8Value value(str);
+
+  std::string our_str = *Nan::Utf8String(str);
+
+  return our_str[0];
 }
 
 /* SALT GENERATION */
@@ -118,7 +121,7 @@ NAN_METHOD(GenerateSalt) {
         return;
     }
 
-    const char minor_ver = ToCharVersion(info[0]->ToString());
+    const char minor_ver = ToCharVersion(Nan::To<v8::String>(info[0]).ToLocalChecked());
     const int32_t rounds = Nan::To<int32_t>(info[1]).FromMaybe(0);
     Local<Object> seed = info[2].As<Object>();
     Local<Function> callback = Local<Function>::Cast(info[3]);
@@ -147,7 +150,7 @@ NAN_METHOD(GenerateSaltSync) {
         return;
     }
 
-    const char minor_ver = ToCharVersion(info[0]->ToString());
+    const char minor_ver = ToCharVersion(Nan::To<v8::String>(info[0]).ToLocalChecked());
     const int32_t rounds = Nan::To<int32_t>(info[1]).FromMaybe(0);
     u_int8_t* seed = (u_int8_t*)Buffer::Data(info[2].As<Object>());
 
@@ -209,8 +212,8 @@ NAN_METHOD(Encrypt) {
         return;
     }
 
-    Nan::Utf8String data(info[0]->ToString());
-    Nan::Utf8String salt(info[1]->ToString());
+    Nan::Utf8String data(Nan::To<v8::String>(info[0]).ToLocalChecked());
+    Nan::Utf8String salt(Nan::To<v8::String>(info[1]).ToLocalChecked());
     Local<Function> callback = Local<Function>::Cast(info[2]);
 
     EncryptAsyncWorker* encryptWorker = new EncryptAsyncWorker(new Nan::Callback(callback),
@@ -228,8 +231,8 @@ NAN_METHOD(EncryptSync) {
         return;
     }
 
-    Nan::Utf8String data(info[0]->ToString());
-    Nan::Utf8String salt(info[1]->ToString());
+    Nan::Utf8String data(Nan::To<v8::String>(info[0]).ToLocalChecked());
+    Nan::Utf8String salt(Nan::To<v8::String>(info[1]).ToLocalChecked());
 
     if (!(ValidateSalt(*salt))) {
         Nan::ThrowError("Invalid salt. Salt must be in the form of: $Vers$log2(NumRounds)$saltvalue");
@@ -309,8 +312,8 @@ NAN_METHOD(Compare) {
         return;
     }
 
-    Nan::Utf8String input(info[0]->ToString());
-    Nan::Utf8String encrypted(info[1]->ToString());
+    Nan::Utf8String input(Nan::To<v8::String>(info[0]).ToLocalChecked());
+    Nan::Utf8String encrypted(Nan::To<v8::String>(info[1]).ToLocalChecked());
     Local<Function> callback = Local<Function>::Cast(info[2]);
 
     CompareAsyncWorker* compareWorker = new CompareAsyncWorker(new Nan::Callback(callback),
@@ -328,8 +331,8 @@ NAN_METHOD(CompareSync) {
         return;
     }
 
-    Nan::Utf8String pw(info[0]->ToString());
-    Nan::Utf8String hash(info[1]->ToString());
+    Nan::Utf8String pw(Nan::To<v8::String>(info[0]).ToLocalChecked());
+    Nan::Utf8String hash(Nan::To<v8::String>(info[1]).ToLocalChecked());
 
     char bcrypted[_PASSWORD_LEN];
     if (ValidateSalt(*hash)) {
@@ -349,7 +352,7 @@ NAN_METHOD(GetRounds) {
         return;
     }
 
-    Nan::Utf8String hash(info[0]->ToString());
+    Nan::Utf8String hash(Nan::To<v8::String>(info[0]).ToLocalChecked());
     u_int32_t rounds;
     if (!(rounds = bcrypt_get_rounds(*hash))) {
         Nan::ThrowError("invalid hash provided");

{'addition_count': 16, 'commit_subject': 'Fix gcc,nan & v8 deprecations', 'deletion_count': 13, 'file_extension': '.cc', 'lang': 'cc', 'license': 'mit', 'repo_name': 'kelektiv/node.bcrypt.js'}