Automating the Generation of iOS Push Notification Certificates

I have a large number (200+) of iOS applications. I needed to generate push notification certificates for each of them. If you’ve ever gone through the process, it can be a huge pain to do just a few. I needed to write a script
to automate this process.

First, I created a ruby gem to access the Mac OS X Keychain App.

Next, I leveraged watir to actually login to the iOS provisioning portal and upload/download the necessary files.

First, make sure that you’re using Mac OS X 10.7 (Lion) and that you have Chrome and Ruby 1.9.2 installed.

  1. Download chromedriver http://code.google.com/p/chromium/downloads/list
  2. Move the binary to /usr/local

Next, run these commands:

git clone git://github.com/jprichardson/GeneratePushCerts.git
gem install 'keychain_manager'
gem install 'watir-webdriver'
cd ./GeneratePushCerts

Modify the ‘config.example.yml’ file with your iOS developer/provisioning portal credentials. Rename the file
to ‘config.yml’.

You’ll want to edit ‘app.rb’ and modify the END_WITH variable and set it to ”. I should have created a regular expression around line 60.

Run the app ‘ruby app.rb’.

Let’s take a look at some watir code from the file:

  browser.checkbox(id: 'enablePush').click() #enable configure buttons
  browser.button(id: 'aps-assistant-btn-prod-en').click() #configure button

  Watir::Wait.until { browser.body.text.include?('Generate a Certificate Signing Request') }

  browser.button(id: 'ext-gen59').click() #on lightbox overlay, click continue

  Watir::Wait.until { browser.body.text.include?('Submit Certificate Signing Request') }

  browser.file_field(name: 'upload').set(CERT_REQUEST_FILE)
  browser.execute_script("callFileValidate();")
  #browser.file_field(name: 'upload').click() #calls some local javascript to validate the file and enable continue button, unfortunately File Browse dialog shows up

  browser.button(id: 'ext-gen75').click()

  Watir::Wait.until(WAIT_TO) { browser.body.text.include?('Your APNs SSL Certificate has been generated.') }

  browser.button(id: 'ext-gen59').click() #continue

  Watir::Wait.until { browser.body.text.include?('Step 1: Download') }

  File.delete(DOWNLOADED_CERT_FILE) if File.exists?(DOWNLOADED_CERT_FILE)

  browser.button(alt: 'Download').click() #download cert

  puts('Checking for existence of downloaded certificate file...')
  while !File.exists?(DOWNLOADED_CERT_FILE)
    sleep 1
  end

  Watir::Wait.until { browser.body.text.include?("Download & Install Your Apple Push Notification service SSL Certificate") }

  browser.button(id: 'ext-gen91').click()
  browser.goto(APP_IDS_URL)

You can browse the entire source code on Github.

I think watir is pretty intuitive and is a swiss army knife for automating the interaction with web pages. It’s pretty slow as it’s meant for testing, so I wouldn’t use it for screen scraping, but it’s served me well for this task.

Do you use Git? If so, checkout Gitpilot to make using Git thoughtless.

Follow me on Twitter: @jprichardson and read my blog on entrepreneurship: Techneur.

-JP Richardson

Automating the Mac OS X Keychain App with Ruby

Recently, I needed a way to automate the generation of 100+ Apple Push notification certificates for my iOS development. So, I created a Ruby Gem [keychain_manager] to automate the Mac OS X Keychain application.

Here is how you can use it:

gem install keychain_manager

require 'keychain_manager'

USER = 'jprichardson@gmail.com'
KEYCHAIN = 'apple_push_keychain' #this can be anything, we just don't want to pollute the 'login' keychain
YOUR_DOWNLOADS_DIR = '' # you must set this, this is where the file aps_production_identity.cer exists

RSA_FILE = '/tmp/myrsa.key'
KeychainManager.generate_rsa_key(RSA_FILE)

CERT_FILE = '/tmp/CertificateSigningRequest.certSigningRequest'
KeychainManager.generate_cert_request(USER, 'US', CERT_FILE) #'US' is the country abbreviation.

kcm = KeychainManager.new(KEYCHAIN)
kcm.delete if kcm.exists?
kcm.create

kcm.import_rsa_key(RSA_FILE)

#now from your browser, you'll have downloaded a file from Apple typically named: aps_production_identity.cer
kcm.import_apple_cert(File.join(YOUR_DOWNLOADS_DIR, '/aps_production_identity.cer'))

P12_FILE = '/tmp/push_prod.p12'
kcm.export_identites(P12_FILE)

PEM_FILE = '/tmp/push_prod.pem'
KeychainManager.convert_p12_to_pem(P12_FILE, PEM_FILE)

kcm.delete

#Now upload the PEM_FILE to your server.

This gem could easily be modified to support other Keychain functions. Browse the sourcecode here: Keychain Manager source code.

I’ll post soon on how I automated the web portion of communicating with the iOS Provisioning Portal.

Do you use Git? If so, checkout Gitpilot to make using Git thoughtless.

Follow me on Twitter: @jprichardson and read my blog on entrepreneurship: Techneur.

-JP Richardson

Using Mongoid with Rspec

I’m a fan of testing. I’m still trying to discipline myself to test before I write code, that’s been a tough habit to develop, however testing after I develop a feature is a good habit that has paid dividends. Lately I’ve started learning how to use Rspec for Rails.

Out of the box, Rspec is configured to use ActiveRecord. I’ve pretty much stopped using relational databases in favor of NoSql solutions. My favorite NoSql DB is MongoDB. The Ruby MongoDB ORM that I’ve been using is Mongoid.

To prep for Rspec, make your gemfile look like this (Assuming Rails 3.x):

gem 'rspec-rails', :group => [:test, :development]
group :test do
  gem 'database_cleaner'
end

Then run:

bundle install
rails g rspec:install

When I started learning how to use Rspec, I started having problems. The first was the following error message:

undefined method `fixture_path=' for # (NoMethodError)

Oops, just needed to comment out the line spec_helper.rb:

config.fixture_path = "#{::Rails.root}/spec/fixtures"

Was I safe yet? Nope. Another error:
undefined method `use_transactional_fixtures=' for # (NoMethodError)

Oops, just needed to comment out the line spec_helper.rb:

config.use_transactional_fixtures = true

I should have known as the there are comments in the file.

Now, when I run my specs, the changes to the database persist from one test to the next. Ideally, you want a clean database when you start each test. This is where the gem database_cleaner comes in handy.

Then add this to your spec_helper.rb file:

  config.before(:suite) do
    DatabaseCleaner[:mongoid].strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner[:mongoid].start
  end

  config.after(:each) do
    DatabaseCleaner[:mongoid].clean
  end

That’s it!

Are you a Git user? Let me help you make project management with Git simple. Checkout Gitpilot.

If you made it this far, read my blog on software entrepreneurship and follow me on Twitter: @jprichardson.

Disable Sprockets for Rails in Development Mode

Sprockets (is/are)? the technology in Rails 3.1 and up that combines your CSS and Javascript files into one CSS and Javascript file. It remains to be seen if this was a positive change or not. The argument is that the client only has to make one HTTP request instead of many for each file; this is a good thing. However, if you change one line in one of your Javascript files, the client then has to redownload the entire combined file instead of just the one Javascript file that you modified.

Regardless, you may want to disable Sprockets while you’re developing your Rails application. This will aid in debugging.

Change…

<%= stylesheet_include_tag "application" %>
<%= javascript_include_tag "application" %>

to…

<%= stylesheet_include_tag "application", debug: Rails.env.development? %>
<%= javascript_include_tag "application", debug: Rails.env.development? %>

Are you a Git user? Let me help you make project management with Git simple. Checkout Gitpilot.

Follow me on Twitter: @jprichardson and read my blog on software entrepreneurship: Techneur

-JP

Feedzirra and Rails 3

Feedzirra is probably one of the best Ruby RSS parsers. But if you’re using it with Rails 3, you may get an error message like so:

no such file to load -- active_support/core_ext/time

If that happens, locate your feedzirra.rb file on your machine and comment out the lines:

#require 'active_support/core_ext/object'
#require 'active_support/core_ext/time'

Add these lines:
require 'active_support/core_ext'
require 'active_support/time'

Are you a Git user? Let me help you make project management with Git simple. Checkout Gitpilot.

Follow me on Twitter @jprichardson and read my blog on building a software business.

Mongoid UTC Times

By default Mongoid will store your Time objects in your local timezone. It’s not made clear on the installation page, but all you have to do is add “use_utc: true” to the defaults in your mongoid.yml configuration file. Yes Virginia, it’s that simple.

Are you a Git user? Let me help you make project management with Git simple. Checkout Gitpilot.

-JP

RVM Is a Must for the Rubyist

If you are a Ruby or Rails developer and you haven’t heard of RVM yet, I’ll let you in on the secret. It rocks! Basically, RVM allows you to easily simultaneously run multiple ruby version on the same machine. You see, Rails 3.0 just came out and I thought it would run on Ruby 1.9.1 but it won’t. It require’s Ruby 1.9.2. So I upgraded my OS X dev box and manually created the new symlinks. All was well, but I wasn’t sure how my apps that required 1.9.1 would behave. So I researched RVM.

To install on your OS X box, it’s quite simple. Just make sure that you have XCode installed, as you’ll need the GCC.

bash < <( curl http://rvm.beginrescueend.com/releases/rvm-install-head )

That’s all you need to do to install it!

Edit ~./.bash_profile with the following:

[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"  

Open a new shell and you’re ready to rock.

To install a Ruby version 1.9.2, just type:

rvm install 1.9.2

Or for version 1.8.7

rvm install 1.8.7

Switch versions like:

rvm 1.9.2

To see where “ruby” is actually installed you type:

which ruby

You’ll see:

/Users/jp/.rvm/rubies/ruby-1.9.2-p0/bin/ruby

To see the gem path:

gem env path

Its output:

/Users/jp/.rvm/gems/ruby-1.9.2-p0:/Users/jp/.rvm/gems/ruby-1.9.2-p0@global

It’s like magic! Take note: according to the guide, you should NOT run “sudo” to install rvm.

Are you a Git user? Let me help you make project management with Git simple. Checkout Gitpilot.

Read me blog on entrepreneurship: Techneur
Follow me on Twitter: @jprichardson

-JP

Levenshtein in Ruby 1.9

In Ruby 1.8, I would use the gem ‘levenshtein’… well that doesn’t work in 1.9. So you need to install the gem ‘text’.

Then the call is as simple as:

Text::Levenshtein.distance('hello', 'hell')

Are you a Git user? Let me help you make project management with Git simple. Checkout Gitpilot.

Follow me on Twitter: @jprichardson

-JP

Deploying a Rails application on Ubuntu 8.04 LTS with Phusion Passenger and SQL Server 2005

This article will provide step by step instructions for preparing and then deploying a Rails application on Ubuntu 8.04 LTS that uses Microsoft SQL Server 2005.

Install Ruby
sudo apt-get install ruby-full build-essential

Install Apache 2
sudo apt-get install apache2 apache2-mpm-prefork apache2-prefork-dev

Install Ruby Gems
Do not install Ruby Gems from Apt.  This will screw up your Gems repository as Apt and Gems will both want to manage it.  Download the latest Gems package from http://rubyforge.org.  At the time of this writing the latest version is 1.3.  Version 1.3 is also the version that I used.
wget http://rubyforge.org/frs/download.php/43985/rubygems-1.3.0.tgz
tar xzvf rubygems-1.3.0.tgz
cd rubygems-1.3.0
sudo ruby setup.rb
sudo ln -s /usr/bin/gem1.8 /usr/bin/gem
sudo gem update --system

Install Rails
Make sure to install the proper version.  You may need to pass the “–version” flag.
sudo gem install rails

Install Phusion Passenger
This allows us to deploy Rails application with as much simplicity as it takes to deploy a PHP application.  This we can avoid using Mongrel/Proxy Balancing/(Apache|Lighttpd|Nginx).
sudo gem install passenger
sudo passenger-install-apache2-module

Next add the following to your /etc/apache2/apache2.conf file:
LoadModule passenger_module /usr/lib/ruby/gems/1.8/gems/passenger-2.0.3/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib/ruby/gems/1.8/gems/passenger-2.0.3
PassengerRuby /usr/bin/ruby1.8

Install Ruby/ODBC/SQLServer2005 Compatibility
In /etc/profile add the following:
export ODBCINI=/etc/odbc.ini
export ODBCSYSINI=/etc
export FREETDSCONF=/etc/freetds/freetds.conf

Make sure you restart your shell after this!

Now install UnixODBC:
sudo apt-get install unixodbc
sudo apt-get install unixodbc-dev
sudo apt-get install tdsodbc

Now install FreeTDS (stable) from source. The FreeTDS in the Apt repository is version 0.63 and will not work with SQL Server 2005. At the time of this writing, the current stable version is 0.82.
wget ftp://ftp.ibiblio.org/pub/Linux/ALPHA/freetds/stable/freetds-stable.tgz
cd freetds-stable
./configure
make
sudo make install

Edit /etc/freetds/freetds.conf and add the following:
[YOUR_DB_DEFINITION_NAME]
host = 172.24.40.100
port = 1433
tds version = 8.0

Test it with the following:
sqsh -S YOUR_DB_DEFINITION_NAME -U USERNAME -P PASSWORD

Once actually logged in, you can run some SQL and verify the results. Make sure to type “go” after each command and also make sure to “use” the right database.

Now edit /etc/odbc.ini and add the following:
[YOUR_DB_DEFINITION_NAME]
Driver = FreeTDS
Description = ODBC connection via FreeTDS
Trace = No
Servername = YOUR_DB_DEFINITION_NAME
Database = YOUR_ACTUAL_DB_NAME

Edit /etc/odbcinst.ini and add the following:
[FreeTDS]
Description = TDS driver (Sybase/Microsoft SQL)
Driver = /usr/lib/odbc/libtdsodbc.so
Setup = /usr/lib/odbc/libtdsS.so
CPTimeout =
CPReuse =
FileUsage = 1

Now test it….
isql YOUR_DB_DEFINITION_NAME USERNAME PASSWORD

Install Ruby ODBC:
wget http://www.ch-werner.de/rubyodbc/ruby-odbc-0.9995.tar.gz
tar zvxf ruby-odbc-0.9995.tar.gz
cd ruby-odbc-0.9995/
ruby extconf.rb
make
sudo make install

Install ActiveRecord ODBC Adapter
sudo gem install activerecord-odbc-adapter

Edit your database.yml in your application and configure it like…
development:
adapter: odbc
dsn: YOUR_DB_DEFINITION_NAME
username: USERNAME
password: PASSWORD

Now dump your Rails app in /var/www/yourrailsapp and add a new Apache Virtual Host as seen in the previous post. Configure the virtual host DocumentRoot to point to the public directory in Apache2.  Do not forget to change ownership of your rails app to www-data. (chown -R www-data:www-data yourrailsapp) That’s all there is too it! Now you can deploy a number of Rails apps in Apache with little trouble!

Are you a Git user? Let me help you make project management with Git simple. Checkout Gitpilot.

Follow

Get every new post delivered to your Inbox.