Executing user-supplied ruby code on a web server
You can use a "blank slate" as a clean room, and a sandbox in which to set the safe level to 4.
A blank slate an object you've stripped all the methods from:
class BlankSlate
instance_methods.each do |name|
class_eval do
unless name =~ /^__|^instance_eval$|^binding$|^object_id$/
undef_method name
end
end
end
end
A clean room is an object in which context you evaluate other code:
clean_room = BlankSlate.new
Read a command from an untrusted source, then untaint it. Unless untainted, Ruby will refuse to eval the string in a sandbox.
command = gets
command.untaint
Now execute the string in a sandbox, cranking the safe level up as high as it will go. The $SAFE level will go back to normal when the proc ends. We execute the command in the context of the clean room's binding, so that it can only see the methods and variables that the clean room can see (remember, though, that like any object, the clean room can see anything in global scape).
result = proc do
$SAFE = 4
clean_room.instance_eval do
binding
end.eval(command)
end.call
print the result:
p result
How to safely let users run arbitrary Ruby code?
Three suggestions:
1) Take a look at Ruby taint levels. This provides some degree of protection against, eval('evil_code')
type things, etc.
2) Unless user's actually need access to the local file system, use something like fakefs
3) No matter what else you do follow Tronic's suggestion (can be a pain to setup, but limited chroot jails are about the only way to make absolutely sure that user's cannot access resources you don't explicitly want them to).
Why a ruby command runs even if a user don't activate the script yet?
I'm a Ruby user
Welcome to Rails!!
Stateless
Firstly, you need to understand that Rails applications - by virtue of running through HTTP - are stateless, meaning that "state" such as User
or Account
have to be re-established with each new action.
In short, this means that invoking actions/commands on your system have to be done through ajax or another form of server-connectivity.
Many native developers (native apps are stateful) don't understand how Rails / web apps are able to retain "state", and thus make a bunch of mistakes with their code.
receives user's active request
Even if you understand how to set up authentication inside a Rails app, it's important to understand the virtues of it being stateless... EG the above line means you have to have a user signed in and authenticated before you can send the request.
This forms one part of your problem (I'll explain in a second)
ERB
Secondly, the other problem you have is with the ERB nature of Rails.
the ruby code just start on its own even before I click this button.
This happens because you're including pure Ruby code in your front-end scripts. This means that whenever these scripts are loaded (triggered), they will fire.
The bottom line here is you need to put this script on your server. Otherwise it will just run...
Fixes
1. ERB
<%= content_tag :div, class: "page-title" do %>
<%= button_tag "Help Request", class:"btn-send-alert" %>
<%= content_tag :p, "Hello %>
<% end %>
You'll thank me in 1+ months.
Convention over Configuration means you use as many of the Rails helpers as you can. You don't need to go stupid with it, but the more "conventional" your code is, the better it will be for future developers to improve it.
Another tip - only use HTML for formatting; CSS for styling. Don't use
<br>
unless you actually want to break a line.Another tip - never use inline styling - Rails has an adequate asset pipeline into which you should put all your CSS
--
2. Ajax
Secondly, your use of Javascript is incorrect.
More specifically, you're calling a server-based function inside front-end views. To explain this a little more, I'll show you the famed MVC image I post on here a lot:
This is how Rails works (MVC - Model View Controller) - this means that whenever you deal with your application, you have to accommodate a layer of abstraction between the user & your app -- the browser.
By its nature, the browser is not stateful - it stores session cookies which you have to authenticate on the server. You cannot call "server" code in the front-end HTML/JS.
This is why your Ruby code is firing without any interaction, although I'm not sure how it's able to fire in the asset pipeline.
If you want to make it work properly, you'll need to create a controller action to invoke the mailer send function, which you'll be able to do using the following setup:
#config/routes.rb
get :support, to: "application#support", as: :support -> url.com/support
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
respond_to :js, only: :support
def support
Smalier.class_alert(@lesson.current_user).deliver_now
end
end
#app/views/controller/view.html.erb
<%= content_tag :div, class: "page-title" do %>
<%= button_to "Help Request", support_path, method: :get, class:"btn-send-alert" %>
<%= content_tag :p, "Hello" %>
<% end %>
#app/views/application/support.js.erb
alert ("Hello");
Run Ruby file from html form submit
The easiest way is as follows:
Package the
example.rb
code into a class or module like so:class FileReader
def self.read_grammar_defs(filename)
# ...
end
endrequire the file from your sinatra server
Inside the
post
action, read the params and call the method:post '/p' do
@result = FileReader.read_grammar_defs(params[:grammar_file])
erb :home
end
With this code, after submitting the form, it would populate the @result
variable and render the :home
template. Instance variables are accessible from ERB and so you could access it from therer if you wanted to display the result.
This is one potential issue with this, though - when the page is rendered the url will still say "your_host.com/p"
and if the user reloads the page, they will get a 404 / "route not found" error because there is no get "/p"
defined.
As a workaround, you can redirect '/'
and use session
as described in this StackOverflow answer or Sinatra' official FAQ to pass the result value.
Related Topics
Rails. How to Store Time of Day (For Schedule)
Uninitialized Constant Rake::Dsl in Ruby Gem
How to Remove Ruby from Ubuntu
Same Instance Variable for All Actions of a Controller
Heroku Wrongly Detecting My Node App as a Ruby App
Rails - Multiple Top Level Domains and a Single Session/Cookie
Ruby: Compare 2 Arrays for Matches, and Count the Number of Match Instances
Getting Viewable Text Words via Nokogiri
I Want to Override Authenticate_User and Current_User Method of Devise Gem
Where in the Ruby Language Is %Q, %W, etc., Defined
How to Display a PDF in Ror (Ruby)
How to Share Variables Across My .Rb Files
How to Install Ruby-Debug in Ruby 1.9.3/Rails 3.2.1
How to Randomly Iterate Through a Large Range
How to Wrap the Invocation of a Ruby Method by Including a Module