Skip to content

Instantly share code, notes, and snippets.

@evanlucas
Last active December 9, 2016 17:38
Show Gist options
  • Save evanlucas/6d9c5998100e9b1cdbea37ee7d224ad1 to your computer and use it in GitHub Desktop.
Save evanlucas/6d9c5998100e9b1cdbea37ee7d224ad1 to your computer and use it in GitHub Desktop.
allow buffers for crypto.randomBytes
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
index 8f2f750..8912eea 100644
--- a/src/node_crypto.cc
+++ b/src/node_crypto.cc
@@ -5503,14 +5503,21 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> argv[2]) {
ERR_error_string_n(req->error(), errmsg, sizeof errmsg);
argv[0] = Exception::Error(OneByteString(req->env()->isolate(), errmsg));
- argv[1] = Null(req->env()->isolate());
req->release();
} else {
char* data = nullptr;
size_t size;
req->return_memory(&data, &size);
argv[0] = Null(req->env()->isolate());
- argv[1] = Buffer::New(req->env(), data, size).ToLocalChecked();
+
+ if (!argv[1]->IsNull()) {
+ char* buf = reinterpret_cast<char*>(Buffer::Data(argv[1].As<Object>()));
+ for (size_t i = 0; i < size; i++) {
+ buf[i] = data[i];
+ }
+ } else {
+ argv[1] = Buffer::New(req->env(), data, size).ToLocalChecked();
+ }
}
}
@@ -5523,6 +5530,7 @@ void RandomBytesAfter(uv_work_t* work_req, int status) {
HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());
Local<Value> argv[2];
+ argv[1] = Null(env->isolate());
RandomBytesCheck(req, argv);
req->MakeCallback(env->ondone_string(), arraysize(argv), argv);
delete req;
@@ -5534,38 +5542,56 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
// maybe allow a buffer to write to? cuts down on object creation
// when generating random data in a loop
- if (!args[0]->IsUint32()) {
- return env->ThrowTypeError("size must be a number >= 0");
+ if (!args[0]->IsUint32() && !Buffer::HasInstance(args[0])) {
+ return env->ThrowTypeError("size must be a number >= 0 or a buffer");
}
- const int64_t size = args[0]->IntegerValue();
- if (size < 0 || size > Buffer::kMaxLength)
- return env->ThrowRangeError("size is not a valid Smi");
+ if (args[0]->IsUint32()) {
+ const int64_t size = args[0]->IntegerValue();
+ if (size < 0 || size > Buffer::kMaxLength)
+ return env->ThrowRangeError("size is not a valid Smi");
- Local<Object> obj = env->NewInternalFieldObject();
- RandomBytesRequest* req = new RandomBytesRequest(env, obj, size);
+ Local<Object> obj = env->NewInternalFieldObject();
+ RandomBytesRequest* req = new RandomBytesRequest(env, obj, size);
- if (args[1]->IsFunction()) {
- obj->Set(FIXED_ONE_BYTE_STRING(args.GetIsolate(), "ondone"), args[1]);
+ if (args[1]->IsFunction()) {
+ obj->Set(FIXED_ONE_BYTE_STRING(args.GetIsolate(), "ondone"), args[1]);
- if (env->in_domain())
- obj->Set(env->domain_string(), env->domain_array()->Get(0));
- uv_queue_work(env->event_loop(),
- req->work_req(),
- RandomBytesWork,
- RandomBytesAfter);
- args.GetReturnValue().Set(obj);
+ if (env->in_domain())
+ obj->Set(env->domain_string(), env->domain_array()->Get(0));
+ uv_queue_work(env->event_loop(),
+ req->work_req(),
+ RandomBytesWork,
+ RandomBytesAfter);
+ args.GetReturnValue().Set(obj);
+ } else {
+ env->PrintSyncTrace();
+ Local<Value> argv[2];
+ argv[1] = Null(env->isolate());
+ RandomBytesWork(req->work_req());
+ RandomBytesCheck(req, argv);
+ delete req;
+
+ if (!argv[0]->IsNull())
+ env->isolate()->ThrowException(argv[0]);
+ else
+ args.GetReturnValue().Set(argv[1]);
+ }
} else {
+ // Buffer
+ const int64_t size = Buffer::Length(args[0]);
+ Local<Object> obj = env->NewInternalFieldObject();
+ RandomBytesRequest* req = new RandomBytesRequest(env, obj, size);
env->PrintSyncTrace();
+
Local<Value> argv[2];
+ argv[1] = args[0];
RandomBytesWork(req->work_req());
RandomBytesCheck(req, argv);
delete req;
if (!argv[0]->IsNull())
env->isolate()->ThrowException(argv[0]);
- else
- args.GetReturnValue().Set(argv[1]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment