Skip to content

Commit

Permalink
Merge pull request #35 from GabrielCastro/feat/enable-global-this
Browse files Browse the repository at this point in the history
feat: always allow getting global this
  • Loading branch information
GabrielCastro authored Jun 21, 2020
2 parents 1f95916 + 6751376 commit c09f458
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 5 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
Disable Eval
============

![Node.js CI](https://github.com/GabrielCastro/node-disable-eval/workflows/Node.js%20CI/badge.svg?branch=master)
52 changes: 47 additions & 5 deletions lib/index.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,33 @@ using v8::Value;
namespace dynamic_eval {

const char *kEvalCallbackKey = "eval_callback_key";
const char *kEvalPatternKey = "eval_pattern_key";
const char *kEvalPattern = "(\\(\\s*function\\s+anonymous\\s*\\(\\s*\\)\\s*\\{)?"
"\\s*return\\s+this\\s*;?\\s*"
"(\\}\\s*\\))?\\s*";

Local<v8::String> new_string(Local<v8::Context> ctx, const char *string_data) {
return String::NewFromUtf8(ctx->GetIsolate(), string_data, v8::NewStringType::kInternalized).ToLocalChecked();
}

Local<v8::RegExp> getPattern(Local<v8::Context> ctx) {
auto global = ctx->Global();
auto key = new_string(ctx, kEvalPatternKey);
Local<v8::Value> callback = Nan::GetPrivate(global, key).ToLocalChecked();
return callback.As<v8::RegExp>();
}

bool codeIsGlobalThis(Local<v8::Context> ctx, Local<String> str) {
auto regexp = getPattern(ctx);
auto test_method = regexp->Get(new_string(ctx, "test")).As<v8::Function>();
auto args = str.As<v8::Value>();
auto ret = Nan::Call(test_method, regexp.As<v8::Object>(), 1, &args).ToLocalChecked().As<v8::Boolean>();
return ret->IsTrue();
}

bool dynamic_callback(Local<v8::Context> ctx, Local<String> str) {
auto global = ctx->Global();
auto key = String::NewFromUtf8(ctx->GetIsolate(), kEvalCallbackKey);
auto key = new_string(ctx, kEvalCallbackKey);
Local<v8::Value> callback = Nan::GetPrivate(global, key).ToLocalChecked();

bool should_eval;
Expand All @@ -33,6 +56,10 @@ namespace dynamic_eval {
Nan::ThrowTypeError("Unable to find eval callback");
return false;
}

if (!should_eval) {
should_eval = codeIsGlobalThis(ctx, str);
}
return should_eval;
}

Expand All @@ -46,9 +73,14 @@ namespace dynamic_eval {

if (bool_or_callback->IsBoolean()) {
bool allowed = bool_or_callback.As<v8::Boolean>()->Value();
Nan::DeletePrivate(global, private_key);
isolate->SetAllowCodeGenerationFromStringsCallback(nullptr);
ctx->AllowCodeGenerationFromStrings(allowed);
if (allowed) {
Nan::DeletePrivate(global, private_key);
ctx->AllowCodeGenerationFromStrings(true);
} else {
Nan::SetPrivate(global, private_key, bool_or_callback);
isolate->SetAllowCodeGenerationFromStringsCallback(dynamic_callback);
ctx->AllowCodeGenerationFromStrings(false);
}
} else if (bool_or_callback->IsFunction()) {
Nan::SetPrivate(global, private_key, bool_or_callback);
ctx->AllowCodeGenerationFromStrings(false);
Expand All @@ -60,9 +92,19 @@ namespace dynamic_eval {
} // namespace dynamic_eval

void Initialize(Local<Object> exports) {
auto ctx = Nan::GetCurrentContext();
auto isolate = ctx->GetIsolate();
auto global = ctx->Global();

auto private_key = String::NewFromUtf8(isolate, dynamic_eval::kEvalPatternKey, v8::NewStringType::kNormal).ToLocalChecked();
auto pattern_string = String::NewFromUtf8(isolate, dynamic_eval::kEvalPattern, v8::NewStringType::kNormal).ToLocalChecked();
auto pattern = Nan::New<v8::RegExp>(pattern_string, v8::RegExp::kIgnoreCase).ToLocalChecked();

Nan::SetPrivate(global, private_key, pattern);

NODE_SET_METHOD(exports, "setEvalAllowed", dynamic_eval::set_eval_allowed);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

} // namespace uh_no_eval
} // namespace uh_no_eval
16 changes: 16 additions & 0 deletions test/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,19 @@ describe("with a callback", () => {
sinon.assert.calledWith(stub, `(function anonymous(\n) {\nreturn 1\n})`);
});
});

describe('Override for "return this" global', () => {
it("should always return the global object even with eval off", () => {
setEvalAllowed(false);

expect(new Function("return this;")()).toBe(global);
expect(new Function(" return this ")()).toBe(global);
expect(
new Function(`
return this
;
`)()
).toBe(global);
});
});

0 comments on commit c09f458

Please sign in to comment.