Posts tagged: Rails

Rails: Digitally sign outgoing emails (S/MIME)

In this article, I will introduce one method to digitally sign outgoing emails with S/MIME using Ruby on Rails.

require ‘openssl’ vs. Kernel.system openssl

At first, I tried to sign mails using the Ruby OpenSSL library which is basically a lightweight wrapper for libopenssl. However, I was not successful; I found out how to create PKCS7 signatures in general, but not especially for S/MIME mails.

So I decided to use the openssl command line tool that can be invoked like this:

openssl smime -sign -signer $CERT_FILE -passin pass:$CERT_PASS
  -in $UNSIGNED_MAIL -out $SIGNED_MAIL -certfile $CERT_CA_FILE
  -from 'your ' -to 'recipients <email@address>'
  -subject 'The Subject'

This command takes an unsigned MIME mail (located in a file whose path is stored in $UNSIGNED_MAIL), signs it with $CERT_FILE (protected by $CERT_PASS), attaches the Certification Authority’s certificate ($CERT_CA_FILE) and stores the resulting signed mail (which is in multipart/signed format) into $SIGNED_MAIL, setting the From:, To: and Subject: headers appropriately.

Invoking openssl from your mailer

To sign all emails that go out from your mailer (which is probably derived from ActionMailer::Base), you can use this code:

class Notifications < ActionMailer::Base
  CERT_DIR = ‘…’
  CERT_FILE = ‘cert.pem’
  CERT_PASS = ‘passphrase for cert.pem’
  CERT_CA_FILE = ‘your-ca.pem’

  #… your other mailer code …

  # overload deliver! to sign outgoing emails
  def deliver!
    unsigned = Tempfile.new ‘notification-unsigned’
    unsigned.write mail
    unsigned.close

    signed = Tempfile.new ‘notification-signed’
    signed.close

    Kernel.system ‘openssl’, ‘smime’, ‘-sign’, ‘-signer’, CERT_DIR+CERT_FILE, ‘-passin’, ‘pass:’+CERT_PASS,
      ‘-in’, unsigned.path, ‘-out’, signed.path, ‘-certfile’, CERT_DIR+CERT_CA_FILE,
      ‘-from’, ‘YOUR NAME <EMAIL@ADDRESS>’, ‘-to’, mail.to.join(’,’), ‘-subject’, mail.subject
    unsigned.close!

    mail.instance_variable_set ‘@smime_encoded’, File::read(signed.path)
    signed.unlink

    class << mail
      define_method :encoded do
        self.instance_variable_get ‘@smime_encoded’
      end
    end

    super mail
  end
end

This is a bit dirty because the first parameter for “deliver!” is normally a TMail::Mail object whose “encoded” method is called by the delivery method. In the code above, I have replaced the “mail” object (first parameter for “deliver!”) by a String with an attached “encoded” method that returns the string itself. However, it was the most simple working solution I could think of. Please tell me if you know a cleaner solution (re-parsing the signed email into a TMail::Mail object doesn’t work because it changes the signed mail by a few bytes and makes the signature invalid).

The above code assumes that both public (signature) and private key are stored in the $CERT_FILE. If this is not the case for you, you’d have to modify the command line slightly.

Rails: Using HTML typography automatically

There’s a way you can use special characters for HTML typography in Rails without much work: Just let your views about raw text and then overwrite the html_escape (h) method:

module ApplicationHelper

  def h(s)
    super(s). \
      gsub(‘(c)’  , ‘&copy’). \
      gsub(‘(r)’  , ‘&reg;’). \
      gsub(‘(tm)’ , ‘&trade;’). \
      gsub(’ 1/2 ‘, ’ &frac12; ‘). \
      gsub(’ 1/4 ‘, ’ &frac14; ‘). \
      gsub(’ 3/4 ‘, ’ &frac34; ‘). \
      gsub(‘… ‘ , ‘&hellip; ‘). \
      gsub(’ — ‘ , ’ &mdash; ‘). \
      gsub(’ - ‘  , ’ &ndash; ‘)
  end

In this case, three hyphens are replaced by ” — “, three dots by an ellipse etc.

Now just make sure that your views use it correctly and output “--” instead of “-” etc. when it is necessary.

Rails 2.3: Using ActiveRecord from within console application

If you use Ruby on Rails and want to have access to ActiveRecord and all the other nifty features from within a standalone Ruby script (for instance, a cronjob script that checks integrity of your data), all you need to do is including the “environment” script that fully sets up the Rails environment. In this case I use the “../config” path because my script is located in the app’s “scripts” directory.

#!/usr/bin/ruby
require ’../config/environment’

# now all Rails features are available, all plugins loaded etc.

# demo
records = Model.find :all
for r in records
  puts ‘Checking ‘ + r.name + ’ …’
end

Image | WordPress Themes