Avoid executing system command with Ruby secure open - ruby

In terminal, typing:
> irb
> require('open-uri')
> open("| curl http://www.haosou.com").read
can execute a system command. How can I avoid this?

Executing this kind of command is a serious security issue.
You can use a regex to validate the format:
/^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
The validation can be done in a model:
validates_format_of :url, :with => /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
Or elsewhere:
if url =~ /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
require('open-uri')
open(url).read
end

Related

How to cgi escape ruby credentials

I am running the command bundle install and keep getting the following error
Please CGI escape your usernames and passwords before setting them for authentication.
I am unsure how I could go about CGI escaping my credentials- any ideas? Thanks
You can do this in irb with Ruby's CGI::Util module:
$ irb
irb(main):001:0> require "cgi"
=> true
irb(main):002:0> CGI.escape "foo#example.com"
=> "foo%40example.com"

Customising IRB console for gem

I'd like to extend the default console application that is built as standard with bundle gem by applying some of the IRB config options.
Looking at the documentation, I can see that it should be possible for instance to change the prompt, and this works fine on an interactive session. For example I can play with the displayed prompt like this:
2.1.4 :001 > conf.prompt_mode=:SIMPLE
=> :SIMPLE
>>
?> conf.prompt_mode=:DEFAULT
=> :DEFAULT
irb(main):004:0>
However, I cannot find how to translate this into syntax for use in the console app. For example this script:
require 'irb'
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.start
Just starts with the generic configured prompt:
2.1.4 :001 >
I have spent some time trying to find an example use of IRB for a custom repl without loading global defaults, but not found anything I can copy from.
I can see that the undocumented method IRB.setup has something to do with this, it is setting all the config somehow. Is my only option to write my own version of IRB.start that applies my desired config after calling IRB.setup, or is there support for what I want to do built-in but not documented in standard location?
E.g. the following works, but I feel it's a bit heavy handed extending IRB module this way (and also prone to failing if IRB internals change).
require 'irb'
def IRB.custom_start custom_conf = {}
STDOUT.sync = true
IRB.setup(nil)
custom_conf.each do |k,v|
IRB.conf[k] = v
end
if #CONF[:SCRIPT]
irb = IRB::Irb.new(nil, #CONF[:SCRIPT])
else
irb = IRB::Irb.new
end
#CONF[:IRB_RC].call(irb.context) if #CONF[:IRB_RC]
#CONF[:MAIN_CONTEXT] = irb.context
trap("SIGINT") do
irb.signal_handle
end
begin
catch(:IRB_EXIT) do
irb.eval_input
end
ensure
irb_at_exit
end
end
IRB.custom_start :PROMPT_MODE => :SIMPLE
You can apply custom configurations in two ways.
The first one is to use irbrc file. It may be tricky in building console application (calling IRB.start from the ruby file instead of irb from the console).
The second one is the approach that you have described in the post. You can write your own IRB::start method based on the original one. There are exactly the same potential issues as in using undocumented API - it can break in the future with newer versions of irb.
You should think if you really need to build a console application on the top of irb. For example you can solve this problem using Pry. It allows to define configuration before starting interactive session.
require 'irb'
IRB.conf[:PROMPT_MODE] = :SIMPLE
IRB.start
The approach above doesn't work because conf[:PROMPT_MODE] gets over-riden in a method called IRB.init_config here
When IRB.start is called, it calls IRB.setup which in turn calls the method IRB.init_config -- which over-rides conf[:PROMPT_MODE] setting.
Here is one approach which solves the problem (relies on internal knowledge of the implementation).
require 'irb'
module IRB
singleton_class.send(:alias_method, :old_setup, :setup)
def IRB.setup(ap_path)
IRB.old_setup(ap_path)
conf[:PROMPT_MODE] = :SIMPLE
end
end
IRB.start

How do I gain access to number_with_presicion using a ruby script?

Inside my ruby script I would like to use, number_with_presicion. How would I go about this? Include *something* ?
Try this
irb --> require 'action_view'
==> true
irb --> ActionView::Base.new.number_with_precision 1234
==> "1234.000"
You need to require action_view in your ruby script.
UPDATE
To be able to use number_with_precision without typing ActionView::Base, you need to extend Numeric class like this
require 'action_view'
class Numeric
def number_with_precision
ActionView::Base.new.number_with_precision(self)
end
end
After this, you can use it like this
irb --> 10.number_with_precision
==> "10.000"
Obviously, you can put this extension in a file and require that file via require and you'll have the extension available in your Ruby script.
Add this to you script file
include ActionView::Helpers::NumberHelper
now you can use -> new_number = (number_with_precision 3556.22321, :precision => 2)

Error in net/ftp while using sendcmd function

I am new to ruby. I used net/ftp for accessing the remote files. I need to execute the command and get the result from remote machine. How can I do this??
I have tried the following way,
#!/usr/bin/ruby
require 'rubygems'
require 'net/ftp'
require 'fileutils'
URL = 'ip'
username = 'name'
passwd = "pass"
directory = 'path'
filename = 'file'
ftp=Net::FTP.new
ftp.connect(URL,21)
ftp.login(username,passwd)
ftp.chdir(directory)
ftp.sendcmd("fuser filename")
ftp.close
It throw the following error,
/usr/lib/ruby/1.8/net/ftp.rb:243:in `getresp': 500 Unknown command. (Net::FTPPermError)
from /usr/lib/ruby/1.8/net/ftp.rb:264:in `sendcmd'
from /usr/lib/ruby/1.8/monitor.rb:242:in `synchronize'
from /usr/lib/ruby/1.8/net/ftp.rb:262:in `sendcmd'
from connection.rb:20
How can I solve this error?? Please give some suggestion on this..
As I've just found the answer to your question after I've found your question:
To issue site specific commands, add a "SITE" in front of the command:
ftp.sendcmd("SITE fuser #{filename}")

Cron and Ruby.. Does "puts `system command`" do anything?

Quick question on cron with ruby,
I have a script which runs
puts `tar etc..`
I'm trying to debug why this script isn't tarring up the files like it should..
It works fine when I invoke it manually and i see the tar output too..
Does puts actually do anything when its run in a cron job?
Thanks
Daniel
From the crontab helping page:
If standard output and standard error are not redirected by commands executed from the crontab entry, any generated output or errors shall be mailed, via an implementation-defined method, to the user.
What I usually do for debugging crontabs is creating a Logger:
logfile = File.open('/path/to/log.log', 'rw')
logger = Logger.new(logfile)
logger.debug('something')
if you have the privilege to install gems, you can try minitar, instead of depending on system tar.
require 'zlib'
require 'archive/tar/minitar'
include Archive::Tar
File.open('test.tar', 'wb') do |tarfile|
Archive::Tar::Minitar::Writer.open(tarfile) do |tar|
Dir["file*"].each do |file|
if File.file?(file)
tar.add_file(file, :mode =>0644, :mtime =>Time.now) { |stream, io|
stream.write( File.open(file).read )
}
end
end
end
end

Resources