Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add binding to napi_run_script #692

Merged
merged 7 commits into from
Mar 15, 2021
Merged

Conversation

branchseer
Copy link
Contributor

No description provided.

Copy link
Member

@kjvalencik kjvalencik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution! This seems very straight forward, but I would like to discuss the API a bit further. Specifically if this method should be marked unsafe.

crates/neon-runtime/src/napi/string.rs Show resolved Hide resolved
src/types/mod.rs Outdated
@@ -360,6 +360,16 @@ impl JsString {
}
}

#[cfg(feature = "napi-1")]
pub fn run_as_script<'a, C: Context<'a>>(self, cx: &mut C) -> JsResult<'a, JsValue> {
Copy link
Member

@kjvalencik kjvalencik Mar 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dherman What do you think about marking this as unsafe? Even though it's not unsafe by Rust's definition,eval is a very common exploit vector and it could be helpful to signal to users that only trusted input should be used.

Copy link
Contributor Author

@branchseer branchseer Mar 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rustls had a similar case: they wanted to add an option that disables cert verification, which was very unsafe, but not rust unsafe. What they do is put it behind a feature flag and explicitly say "dangerous" on the api.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of adding dangerous to the function name itself. For example, React has a dangerouslySetInnerHTML function. We could call this, dangerously_run_script.

Adding the feature flag seems like additional complexity without any benefit. Unlike with rustls, the run_script API will still exist even if we feature flag it because it's part of Node.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think marking unsafe when it's not about Rust's safety guarantees is generally considered poor form in the Rust ecosystem, so I agree that's not the best approach. Rather than a prefix, how about a module? Some possibilities:

  • neon::danger::run_script
  • neon::advanced::run_script
  • neon::unchecked::run_script
  • neon::reflect::run_script

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should mention, I also agree the feature flag is the wrong approach because it's viral. If a library wants to use the feature they should be able to do it without requiring downstream clients to have to enable the feature flag, and then those clients end up enabling it for everyone anyway, which isn't great either.

Copy link
Collaborator

@dherman dherman Mar 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: @kjvalencik and I spoke this morning, and we came to this suggestion for the naming and documentation:

  • It shouldn't be available in any convenience forms (not on Context or anywhere else)
  • neon::reflect::eval is a good name for it: it shows that it's a reflection API, not something to reach for casually, and it connects it to JS's eval, which is in fact what it is (technically speaking, it's JS's "indirect eval" but you can't implement direct eval as anything other that a syntax in pure JavaScript source code) and also brings along the mindshare from the JS ecosystem about the dangers of eval
  • The API docs should clearly explain that use of eval can be a security risk and should not be used casually

@patr0nus How does that sound?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dherman @kjvalencik

Putting it under neon::reflect sounds good to me.

However I prefer the name run_script rather than eval, since it's a direct binding to napi_run_script, and as you mentioned, it's not quite the same as eval in JS. For example, one might assume neon::reflect::eval can access local variables like JS eval can.

Also I would suggest the function should accept JsString instead of AsRef<str>. If a user wants to be run a script repeatedly, he/she wouldn't want a JsString to be created every time.

TL;DR: I would prefer the function signature to be:

fn neon::reflect::run_script<'a, 'b, C: Context<'a>>(cx: &mut C, script: Handle<'b, JsString>) -> JsResult<'a, JsValue>.

Copy link
Member

@kjvalencik kjvalencik Mar 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, the N-API naming is not optimal. It is identical to indirect eval (as defined by the ECMA spec).

Considering direct eval is not possible in a native context, eval seems more appropriate.

Neon already diverges from n-api in a number of places. For example, Root instead of reference.

Additionally, eval carries the stigma of danger associated with the term, while run_script does not. I think this is very important.

I like accepting JsString. This is somewhat outside the scope of this PR, but we could improve the API by adding a ToJsString trait implemented for Handle<JsString>, &JsString, and anything that's AsRef<str> and making eval generic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems reasonable. I have pushed the changes.
Though I didn't include the documentation which explains the security risk, as I am not a native speaker, so not really suitable for explaining this kind of serious stuff.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem! I am going to be working on API docs next so I can follow up in a future PR with some documentation. Thanks so much for your work!

Copy link
Collaborator

@dherman dherman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: (moved this to the appropriate sub-thread)

branchseer and others added 5 commits March 13, 2021 21:42
# Conflicts:
#	crates/neon-runtime/src/napi/bindings/functions.rs
# Conflicts:
#	crates/neon-runtime/src/napi/bindings/functions.rs
#	src/lib.rs
@kjvalencik
Copy link
Member

@patr0nus Thanks for the contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants