Skip to content

Instantly share code, notes, and snippets.

@r
Created January 17, 2010 23:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save r/279650 to your computer and use it in GitHub Desktop.
Save r/279650 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# update_profile_background_image.rb
#
# a simple example of how to construct the OAuth signatures necessary to upload
# a background image to a Twitter profile page. this will call
# account/update_profile_background_image.xml with the contents of
# 'background.png' (must be in the same directory as this script). care has
# been given to document this script, as well as to correlate lines in this
# script with the OAuth Core 1.0 specification (http://oauth.net/core/1.0/).
#
# to use this script fill in the CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN,
# and TOKEN_SECRET variables below.
#
# this script is meant to be exemplary, and has not been designed to be used
# in a production-like situation. every part of the OAuth request generation
# is illustrated save for the actual HMAC-SHA1 digest creation -- that is
# handled by hmac-sha1.
#
# raffi krikorian <raffi@twitter.com>
require 'base64' # used to base-64 encode strings
require 'cgi' # used for URL escaping strings
require 'curb' # used to wrap cURL and to make the calls to Twitter
require 'hmac-sha1' # used to perform the HMAC-SHA1 digest creation
# POST account/update_profile_background_image
# - image. Required. Must be a valid GIF, JPG, or PNG image of less than 800 KB
# in size. Images with width larger than 2048 pixels will be forceably
# scaled down.
# - tile. Optional. If set to true the background image will be displayed
# tiled. The image will not be tiled otherwise.
BACKGROUND_UPLOAD_URL=
'http://twitter.com/account/update_profile_background_image.xml'
# tokens that are required for this application -- see section 3 for the
# definitions of these variables.
#
# the CONSUMER_KEY and CONSUMER_SECRET are for this "application". you can
# create an application at http://twitter.com/oauth_clients and then copy and
# paste these variables in.
CONSUMER_KEY=''
CONSUMER_SECRET=''
# the ACCESS_TOKEN and TOKEN_SECRET are strings that identify a particular
# user using this particular application (as identified by CONSUMER_KEY/
# CONSUMER_SECRET).
#
# to obtain these tokens, a user needs to go through the OAuth workflow.
ACCESS_TOKEN=''
TOKEN_SECRET=''
# a simple test to make sure those are set and this script is not just being
# run
if (CONSUMER_KEY == '' || CONSUMER_SECRET == '' ||
ACCESS_TOKEN == '' || TOKEN_SECRET == '')
puts 'make sure to set CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, and ' +
'TOKEN_SECRET before running this script'
exit 1
end
# simple patches to the Array class
class Array
# given an array of strings, URL escape each string, and then join the
# strings together with a '&' character. return the joined string.
def escape_and_join; map{ |s| CGI::escape(s) }.join('&'); end
# given an array of strings, concatenate the strings together, and then
# return the base-64 encoded version of the string.
def encode64; join.encode64; end
end
# simple patch to the String class
class String
# given a string, base-64 encode it and return.
def encode64; Base64.encode64(self).chomp; end
end
# a simple helper function that will generate a random 128 bits
def nonce; (['0'] * 16).fill{ |i| rand(256).chr }.encode64; end
# collect together all the parameters that we are going to use to sign the
# request. these variables are defined in sections 7 and 8. we are going to
# use these parameters to generate the signature.
parameters = {
'oauth_consumer_key' => CONSUMER_KEY,
'oauth_token' => ACCESS_TOKEN,
'oauth_nonce' => nonce,
'oauth_timestamp' => Time.new.to_i,
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_version' => '1.0'
}
# join the parameters together -- see section 9.1.1.
parameters_string =
parameters.sort.map{ |k,v| "#{k}=#{CGI::escape(v.to_s)}" }.join('&')
# construct the base string used for signature generation -- see sections 9.1.2
# and 9.1.3.
base_string = ['POST', BACKGROUND_UPLOAD_URL, parameters_string].escape_and_join
# create the encryption key used to feed to HMAC-SHA1 -- see section 9.2.
encryption_key = [CONSUMER_SECRET, TOKEN_SECRET].escape_and_join
# generate the signature from the base string and the encryption key -- see
# section 9.2.1.
signature = CGI::escape(HMAC::SHA1.digest(encryption_key, base_string).encode64)
# create the authorization header string -- see appendix a.5.3 for an example
# of what this string should look like
authorization_parameters =
parameters.map{ |k,v| "#{k}=\"#{CGI::escape(v.to_s)}\"" } << "oauth_signature=\"#{signature}\""
authorization_header_string = (["OAuth realm=\"http://twitter.com/\""] + authorization_parameters).join(',')
# make the request to the BACKGROUND_UPLOAD_URL endpoint
c = Curl::Easy.new(BACKGROUND_UPLOAD_URL)
c.headers['Expect'] = '' # erase the 'Expect' header
# put the oauth authorization header value into the 'Authorization' header
c.headers['Authorization'] = authorization_header_string
# upload the image using multipart form post (rfc 1867)
c.multipart_form_post = true
c.http_post(Curl::PostField.file('image', 'background.jpg'))
# print out the response
puts c.body_str
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment