tags:

views:

31

answers:

1

I was just reading a blog post about sanitizing user input in Ruby before sending it to the command line. The author's conclusion was: don't send user input it to the command line in the first place.

In creating a contact form, he said he learned that

What I should do instead is open a pipe to the mail command as an IO stream and just write to it like any other file handle.

This is the code he used:

open( %Q{| mail -s "#{subject}" "#{recipient}" }, 'w' ) do |msg|
  msg << body
end

(I actually added the quotes around recipient - they're needed, right?)

I don't quite understand how this works. Could anybody walk me through it?

+3  A: 

OK, I'll explain it with the caveat that I don't think it's the best way to accomplish that task (see comments to your question).

open() with a pipe/vertical bar as the first character will spawn a shell, execute the command, and pass your input into the command through a unix-style pipe. For example the unix command cat file.txt | sort will send the contents of the file to the sort command. Similarly, open("| sort", 'w') {|cmd| cmd << file} will take the content of the file variable and send it to sort. (The 'w' means it is opened for writing).

The %Q() is an alternate way to quote a Ruby string. This way it doesn't interfere with literal quote characters in the string which can result in ugly escaping. So the mail -s command is being executed with a subject and a recipient.

Quotes are needed around the subject, because the mail command will be interpreted by the shell, and arguments are separated by spaces, so if you want spaces in an argument, you surround it with quotes. Since the -s argument is for the subject, it needs to be in quotes because it will likely contain spaces. On the other hand, the recipient is an email address and email addresses don't contain spaces, so they're not necessary.

The block is providing the piped input to the command. Everything you add to the block variable (in this case msg) is sent into the pipe. Thus the email body is being appended (via the << operator) to the message, and therefore piped to the mail command. The unix equivalent is something like this: cat body.txt | mail -s "subject" [email protected]

Mark Thomas