jessedoyle / duktape.cr

Evaluate JavaScript from Crystal!
MIT License
137 stars 17 forks source link

decode base64 #25

Closed kostya closed 7 years ago

kostya commented 7 years ago

i trying to decode as in doc: http://duktape.org/1.4.0/guide.html#builtin-duktape-dec

var result = Duktape.dec('base64', 'Zm9v');

but get error: identifier 'Duktape' undefined what i missing?

jessedoyle commented 7 years ago

Hey @kostya, thanks for using Duktape.cr!

Are you using a Duktape::Sandbox instance or a Duktape::Context instance to evaluate your code?

The reason is that Duktape::Sandbox instances will unset the Duktape global javascript object as suggested here. You can see the process here.

kostya commented 7 years ago

i need eval a js code with passing arguments and return value, i not find how to do it with Sandbox, so use runtime.

      decoder = <<-JS
        function decode(arg1, arg2, arg3, arg4) {
          var arg4 = Duktape.dec('base64', arg4);
          ...
          return ...;
        }
      JS

      rt = Duktape::Runtime.new do |sbx|
        sbx.eval! decoder
      end

      res = rt.call("decode", "...", "...", "...", Base64.encode(data))

arg4 here passed binary string, with non unicode chars, it cutted (bug?). So i trying to pass it as base64. But how to decode it?

identifier 'Duktape' undefined
jessedoyle commented 7 years ago

Ah I see. I believe that Duktape::Runtime uses a Sandbox as a context, therefore it does not have the Duktape global object defined.

There are two obvious solutions:

  1. Add an initialize method to Duktape::Runtime that accepts a context : Dukatpe::Context parameter. We would have to make the runtime's @context instance variable a union of Duktape::Sandbox and Duktape::Context.
  2. Modify Duktape::Sandbox to optionally prevent calling the secure! method on initialize. This would give sandboxes access to the Duktape global object.

I think option 1 is the better option in this case. I'm open to PRs, but I can take a look into these modifications in the next few weeks.

What do you think @kostya?

kostya commented 7 years ago

i dont known about 1,2, this is too internal :) can you suggest some hot fix?

jessedoyle commented 7 years ago

Yes, I'm sure there's a quick solution that I can suggest. I'll do some thinking on it and get back to you later today (away from my dev environment right now).

jessedoyle commented 7 years ago

This is definitely not perfect, but here's a quick (hack) monkey patch along the lines that I'm thinking:

require "duktape/runtime"

module Duktape
  class Runtime
    @context : Duktape::Sandbox | Duktape::Context

    def initialize(context : Duktape::Context, &block)
      @context = context
      yield @context
      reset_stack!
    end
  end
end

ctx = Duktape::Context.new
rt = Duktape::Runtime.new(ctx) do |context|
  # initialization code
end

rt.eval "Duktape.dec('base64', 'SGVsbG8=')" # => "Hello"
kostya commented 7 years ago

thanks, works

jessedoyle commented 7 years ago

I'm going to reopen this issue. I feel this should be a part of the core bindings and users should not have to resort to monkey patching to achieve this type of functionality.

I'll look at implementing this functionality over the next few weeks.

If anyone wants to take a stab at a PR, feel free!