Class: Shikashi::Sandbox

Inherits:
Object
  • Object
show all
Defined in:
lib/shikashi/sandbox.rb

Overview

The sandbox class run the sandbox, because of internal behaviour only can be use one instance of sandbox by thread (each different thread may have its own sandbox running in the same time)

Example

require “rubygems” require “shikashi”

include Shikashi

s = Sandbox.new priv = Privileges.new priv.allow_method :print

s.run(priv, ‘print “hello worldn”’)

Defined Under Namespace

Classes: EvalhookHandler, Packet

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSandbox

Returns a new instance of Sandbox.



87
88
89
90
91
92
93
94
95
# File 'lib/shikashi/sandbox.rb', line 87

def initialize
  @privileges = Hash.new
  @chain = Hash.new
  @hook_handler_list = Array.new
  @hook_handler = instantiate_evalhook_handler
  @hook_handler.sandbox = self
  @base_namespace = create_adhoc_base_namespace
  @hook_handler.base_namespace = @base_namespace
end

Instance Attribute Details

#chainObject (readonly)

Binding of execution, the default is a binding in a global context allowing the definition of module of classes



68
69
70
# File 'lib/shikashi/sandbox.rb', line 68

def chain
  @chain
end

#hook_handlerObject (readonly)

Returns the value of attribute hook_handler.



70
71
72
# File 'lib/shikashi/sandbox.rb', line 70

def hook_handler
  @hook_handler
end

#privilegesObject (readonly)

array of privileges of restricted code within sandbox

Example sandbox.privileges.allow_method :raise



66
67
68
# File 'lib/shikashi/sandbox.rb', line 66

def privileges
  @privileges
end

Class Method Details

.run(*args) ⇒ Object

Same as Sandbox.new.run



76
77
78
# File 'lib/shikashi/sandbox.rb', line 76

def self.run(*args)
  Sandbox.new.run(Shikashi.global_binding, *args)
end

Instance Method Details

#add_source_chain(outer, inner) ⇒ Object

add a chain of sources, used internally



98
99
100
# File 'lib/shikashi/sandbox.rb', line 98

def add_source_chain(outer, inner)
  @chain[inner] = outer
end

#base_namespaceObject



102
103
104
# File 'lib/shikashi/sandbox.rb', line 102

def base_namespace
  @base_namespace
end

#create_hook_handler(*args) ⇒ Object



419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/shikashi/sandbox.rb', line 419

def create_hook_handler(*args)
  hook_handler = instantiate_evalhook_handler
  hook_handler.sandbox = self
  @base_namespace = args.pick(:base_namespace) do create_adhoc_base_namespace end
  hook_handler.base_namespace = @base_namespace

  source = args.pick(:source) do generate_id end
  privileges_ = args.pick(Privileges,:privileges) do Privileges.new end

  self.privileges[source] = privileges_

  hook_handler
end

#disposeObject



433
434
435
# File 'lib/shikashi/sandbox.rb', line 433

def dispose
  @hook_handler_list.each(&:dispose)
end

#generate_idObject



83
84
85
# File 'lib/shikashi/sandbox.rb', line 83

def generate_id
  "sandbox-#{rand(1000000)}"
end

#packet(*args) ⇒ Object

Creates a packet of code with the given privileges to execute later as many times as neccessary

(see examples)

Arguments

:code Mandatory argument of class String with the code to execute restricted in the sandbox :privileges Optional argument of class Shikashi::Sandbox::Privileges to indicate the restrictions of the

code executed in the sandbox. The default is an empty Privileges (absolutly no permission)
Must be of class Privileges or passed as hash_key (:privileges => privileges)

:source Optional argument to indicate the “source name”, (visible in the backtraces). Only can

be specified as hash parameter

:base_namespace Alternate module to contain all classes and constants defined by the unprivileged code

if not specified, by default, the base_namespace is created with the sandbox itself

:no_base_namespace Specify to do not use a base_namespace (default false, not recommended to change) :encoding Specify the encoding of source (example: “utf-8”), the encoding also can be

specified on header like a ruby normal source file

NOTE: arguments are the same as for Sandbox#run method, except for timeout and binding which can be used when calling Shikashi::Sandbox::Packet#run

Example:

require “rubygems” require “shikashi”

include Shikashi

sandbox = Sandbox.new

privileges = Privileges.allow_method(:print)

# this is equivallent to sandbox.run(‘print “hello worldn”’) packet = sandbox.packet(‘print “hello worldn”’, privileges) packet.run



380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
# File 'lib/shikashi/sandbox.rb', line 380

def packet(*args)
  code = args.pick(String,:code)
  base_namespace = args.pick(:base_namespace) do nil end
  no_base_namespace = args.pick(:no_base_namespace) do @no_base_namespace end
  privileges_ = args.pick(Privileges,:privileges) do Privileges.new end
  encoding = get_source_encoding(code) || args.pick(:encoding) do nil end

  hook_handler = nil

  if base_namespace
    hook_handler = instantiate_evalhook_handler
    hook_handler.base_namespace = base_namespace
    hook_handler.sandbox = self
  else
    hook_handler = @hook_handler
    base_namespace = hook_handler.base_namespace
  end
  source = args.pick(:source) do generate_id end

  self.privileges[source] = privileges_

  code = "nil;\n " + code

  unless no_base_namespace
    if (eval(base_namespace.to_s).instance_of? Module)
      code = "module #{base_namespace}\n #{code}\n end\n"
    else
      code = "class #{base_namespace}\n #{code}\n end\n"
    end
  end

  if encoding
    code = "# encoding: #{encoding}\n" + code
  end

  evalhook_packet = @hook_handler.packet(code)
  Shikashi::Sandbox::Packet.new(evalhook_packet, privileges_, source)
end

#run(*args) ⇒ Object

Run the code in sandbox with the given privileges (see examples)

Arguments

:code Mandatory argument of class String with the code to execute restricted in the sandbox :privileges Optional argument of class Shikashi::Sandbox::Privileges to indicate the restrictions of the

code executed in the sandbox. The default is an empty Privileges (absolutly no permission)
Must be of class Privileges or passed as hash_key (:privileges => privileges)

:binding Optional argument with the binding object of the context where the code is to be executed

The default is a binding in the global context

:source Optional argument to indicate the “source name”, (visible in the backtraces). Only can

be specified as hash parameter

:timeout Optional argument to restrict the execution time of the script to a given value in seconds

(accepts integer and decimal values), when timeout hits Shikashi::Timeout::Error is raised

:base_namespace Alternate module to contain all classes and constants defined by the unprivileged code

if not specified, by default, the base_namespace is created with the sandbox itself

:no_base_namespace Specify to do not use a base_namespace (default false, not recommended to change) :encoding Specify the encoding of source (example: “utf-8”), the encoding also can be

specified on header like a ruby normal source file

The arguments can be passed in any order and using hash notation or not, examples:

sandbox.run code, privileges sandbox.run code, :privileges => privileges sandbox.run :code => code, :privileges => privileges sandbox.run code, privileges, binding sandbox.run binding, code, privileges #etc sandbox.run binding, code, privileges, :source => source sandbox.run binding, :code => code, :privileges => privileges, :source => source

Example:

require “rubygems” require “shikashi”

include Shikashi

sandbox = Sandbox.new privileges = Privileges.new privileges.allow_method :print sandbox.run(‘print “hello worldn”’, :privileges => privileges)

Example 2: require “rubygems” require “shikashi”

include Shikashi

sandbox = Sandbox.new privileges = Privileges.new privileges.allow_method :print privileges.allow_method :singleton_method_added

sandbox.run(‘

def self.foo
  print "hello world\n"
end
 ', :privileges => privileges)


340
341
342
# File 'lib/shikashi/sandbox.rb', line 340

def run(*args)
  run_i(*args)
end