Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 178 lines (148 sloc) 5.298 kb
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
1 require 'rubygems'
2 require 'hmac-sha1'
3 require 'base64'
d23a7af @davetron5000 broke SignedURL into its own file
authored
4
5 module Gliffy
b0ca557 @davetron5000 ensures method is uppercased
authored
6
d23a7af @davetron5000 broke SignedURL into its own file
authored
7 # Handles signing and assembling the URL
8 class SignedURL
9
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
10 READ_ONLY_PARAMS = {
11 'oauth_consumer_key' => true,
12 'oauth_token' => true,
13 'oauth_signature_method' => true,
14 'oauth_version' => true,
15 'oauth_nonce' => true,
16 'oauth_timestamp' => true,
17 }
18
698e922 @davetron5000 url parts are encoded first
authored
19 # Encodes each part of this url, accounting for some
20 # of the weirdness we are dealing with
21 def self.encodeParts(url)
22 parts = url.split(/\//).map do |part|
23 if part =~ /^\$/
24 part
25 else
26 encode(part)
27 end
28 end
29 parts.join('/')
30 end
31
32 # Ruby's CGI::encode doesn't encode spaces correctly
25936c2 @davetron5000 Fixed bugs in OAuth signing procedure
authored
33 def self.encode(string)
34 string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
698e922 @davetron5000 url parts are encoded first
authored
35 '%' + $1.unpack('H2' * $1.size).join('%').upcase
25936c2 @davetron5000 Fixed bugs in OAuth signing procedure
authored
36 end.gsub(' ', '%20')
37 end
38
12a35b3 @davetron5000 Request layer implemented and tested
authored
39 # Modify the logger
40 attr_accessor :logger
41
5ec97c8 @davetron5000 updated documentation
authored
42 # Create a new SignedURL
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
43 #
5ec97c8 @davetron5000 updated documentation
authored
44 # [+credentails+] The credentials available when signing the request (required).
45 # [+url+] The URL (without parameters) to request (required)
46 # [+method+] The HTTP Request method that will be made (required)
12a35b3 @davetron5000 Request layer implemented and tested
authored
47 def initialize(credentials,url,method,logger=nil)
272806a @davetron5000 broke out secrets et. al. into new object
authored
48 raise ArgumentError.new("credentials is required") if credentials.nil?
49 raise ArgumentError.new("url is required") if url.nil?
50 raise ArgumentError.new("method is required") if method.nil?
51
5029556 @davetron5000 need to hold onto credentials
authored
52 @credentials = credentials
53
12a35b3 @davetron5000 Request layer implemented and tested
authored
54 @logger = logger || Logger.new(STDOUT)
55 @logger.level = Logger::INFO
272806a @davetron5000 broke out secrets et. al. into new object
authored
56
57 @params = {
58 'oauth_signature_method' => 'HMAC-SHA1',
59 'oauth_version' => '1.0',
60 }
61 @params['oauth_consumer_key'] = credentials.consumer_key
25f2b15 @davetron5000 Created a token class and refactored
authored
62 @params['oauth_token'] = credentials.access_token.token if credentials.access_token
272806a @davetron5000 broke out secrets et. al. into new object
authored
63 @consumer_secret = credentials.consumer_secret
458de4c @davetron5000 added warnings and addressed them.
authored
64 if credentials.access_token
65 @access_secret = credentials.access_token.secret
66 else
67 @access_secret = nil
68 end
272806a @davetron5000 broke out secrets et. al. into new object
authored
69 @method = method.upcase
70 @url = url
d23a7af @davetron5000 broke SignedURL into its own file
authored
71 end
72
73 # Sets a request parameter
74 #
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
75 # [param] the name of the parameter, as a string or symbol
d23a7af @davetron5000 broke SignedURL into its own file
authored
76 # [value] the value of the parameter, unencoded
77 #
78 def []=(param,value)
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
79 raise ArgumentError.new("param may not be nil") if param.nil?
80 param = param.to_s
81 raise ArgumentError.new("You may not override #{param}") if READ_ONLY_PARAMS[param]
6454011 @davetron5000 you can now override the protocol per request
authored
82 if value.nil?
83 @params.delete(param)
84 else
85 @params[param] = value.to_s
86 end
d23a7af @davetron5000 broke SignedURL into its own file
authored
87 end
88
89 # Sets all request parameters to those in the hash.
90 def params=(params_hash)
12a35b3 @davetron5000 Request layer implemented and tested
authored
91 raise ArgumentError.new('you may not set params to nil') if params_hash.nil?
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
92 params_hash.each do |k,v|
93 self[k]=v
94 end
d23a7af @davetron5000 broke SignedURL into its own file
authored
95 end
96
97 # Gets the full URL, signed and ready to be requested
12a35b3 @davetron5000 Request layer implemented and tested
authored
98 def full_url(timestamp=nil,nonce=nil)
838fd71 @davetron5000 refactored signature method
authored
99
d23a7af @davetron5000 broke SignedURL into its own file
authored
100 @logger.debug("Getting full_url of #{@url}")
25936c2 @davetron5000 Fixed bugs in OAuth signing procedure
authored
101 @logger.debug("OAuth Part 1 : #{@method}")
838fd71 @davetron5000 refactored signature method
authored
102
25936c2 @davetron5000 Fixed bugs in OAuth signing procedure
authored
103 escaped_url = SignedURL::encode(@url)
104 to_sign = @method + "&" + escaped_url + "&"
838fd71 @davetron5000 refactored signature method
authored
105
25936c2 @davetron5000 Fixed bugs in OAuth signing procedure
authored
106 @logger.debug("OAuth Part 2 (raw) : #{@url}")
107 @logger.debug("OAuth Part 2 (esc) : #{escaped_url}")
838fd71 @davetron5000 refactored signature method
authored
108
b27fbc8 @davetron5000 fixed odd code and added debugging
authored
109 timestamp=Time.now.to_i if timestamp.nil?
110 nonce=@credentials.nonce if nonce.nil?
111
838fd71 @davetron5000 refactored signature method
authored
112 param_part,url_params = handle_params(timestamp,nonce)
25936c2 @davetron5000 Fixed bugs in OAuth signing procedure
authored
113 escaped_params = SignedURL::encode(param_part)
114 @logger.debug("OAuth Part 3 (raw) : #{param_part}")
115 @logger.debug("OAuth Part 3 (esc) : #{escaped_params}")
116
117 to_sign += escaped_params
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
118
838fd71 @davetron5000 refactored signature method
authored
119 signature = get_signature(to_sign)
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
120
838fd71 @davetron5000 refactored signature method
authored
121 url_params['oauth_signature'] = SignedURL::encode(signature)
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
122
b27fbc8 @davetron5000 fixed odd code and added debugging
authored
123 assembled_url = assemble_url(url_params)
124 @logger.debug("Full URL is " + assembled_url)
125 return assembled_url
838fd71 @davetron5000 refactored signature method
authored
126 end
d23a7af @davetron5000 broke SignedURL into its own file
authored
127
838fd71 @davetron5000 refactored signature method
authored
128 private
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
129
838fd71 @davetron5000 refactored signature method
authored
130 def assemble_url(url_params)
9eeb6b5 @davetron5000 OAuth style signing implemented
authored
131 url = @url + '?'
d23a7af @davetron5000 broke SignedURL into its own file
authored
132 url_params.keys.sort.each do |key|
25936c2 @davetron5000 Fixed bugs in OAuth signing procedure
authored
133 val = url_params[key]
d23a7af @davetron5000 broke SignedURL into its own file
authored
134 url += "#{key}=#{val}&"
135 end
136 url.gsub!(/\&$/,'')
137 return url
138 end
838fd71 @davetron5000 refactored signature method
authored
139
140 def get_signature(to_sign)
141 signing_key = get_signing_key
142 @logger.debug("Signing '#{to_sign}' with key '#{signing_key}'")
143
144 sha1 = HMAC::SHA1.new(signing_key)
145 sha1 << to_sign
146 signature = Base64.encode64(sha1.digest())
147 signature.chomp!
148 @logger.debug("signature == '#{signature}'")
149 signature
150 end
151
152 def get_signing_key
153 SignedURL::encode(@consumer_secret) + "&" + SignedURL::encode(@access_secret.nil? ? "" : @access_secret)
154 end
155
156 def handle_params(timestamp,nonce)
157 url_params = Hash.new
158 param_part = ""
159 params = @params
160 params['oauth_timestamp'] = timestamp.to_s
161 params['oauth_nonce'] = nonce
b27fbc8 @davetron5000 fixed odd code and added debugging
authored
162 params.keys.sort.each do |key|
163 value = params[key]
838fd71 @davetron5000 refactored signature method
authored
164 raise ArgumentError.new("#{key} is nil; don't set params to be nil") if value.nil?
165
166 @logger.debug("Adding param #{key} with value #{value} escaped as #{SignedURL::encode(value)}")
167 param_part += SignedURL::encode(key)
168 param_part += "="
169 param_part += SignedURL::encode(value)
170 param_part += '&'
171 url_params[key] = SignedURL::encode(value)
172 end
173 param_part.gsub!(/&$/,'')
174 [param_part,url_params]
175 end
d23a7af @davetron5000 broke SignedURL into its own file
authored
176 end
177 end
Something went wrong with that request. Please try again.