From 3b6200b8ab3abafe0f993106df4ccb3e93a2fd08 Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Thu, 8 May 2014 16:46:43 -0700 Subject: [PATCH 01/11] First pass at adding OAuth2 as an authorization mechanism, enabled via the `auth_type` configuration setting, defaults to "oauth" --- dropbox-api.gemspec | 1 + lib/dropbox-api.rb | 1 + lib/dropbox-api/connection.rb | 5 +++-- lib/dropbox-api/connection/requests.rb | 2 +- lib/dropbox-api/util/config.rb | 2 ++ lib/dropbox-api/util/oauth2.rb | 28 ++++++++++++++++++++++++++ 6 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 lib/dropbox-api/util/oauth2.rb diff --git a/dropbox-api.gemspec b/dropbox-api.gemspec index 481d4aa..4d353ef 100644 --- a/dropbox-api.gemspec +++ b/dropbox-api.gemspec @@ -15,6 +15,7 @@ Gem::Specification.new do |s| s.add_dependency 'multi_json' s.add_dependency 'oauth' + s.add_dependency 'oauth2' s.add_dependency 'hashie' s.files = `git ls-files`.split("\n") diff --git a/lib/dropbox-api.rb b/lib/dropbox-api.rb index e7ea3cb..493d90a 100644 --- a/lib/dropbox-api.rb +++ b/lib/dropbox-api.rb @@ -11,6 +11,7 @@ module API require "dropbox-api/version" require "dropbox-api/util/config" require "dropbox-api/util/oauth" +require "dropbox-api/util/oauth2" require "dropbox-api/util/error" require "dropbox-api/util/util" require "dropbox-api/objects/object" diff --git a/lib/dropbox-api/connection.rb b/lib/dropbox-api/connection.rb index b57dce7..d4d18ae 100644 --- a/lib/dropbox-api/connection.rb +++ b/lib/dropbox-api/connection.rb @@ -15,8 +15,9 @@ def initialize(options = {}) @consumers = {} @tokens = {} Dropbox::API::Config.endpoints.each do |endpoint, url| - @consumers[endpoint] = Dropbox::API::OAuth.consumer(endpoint) - @tokens[endpoint] = Dropbox::API::OAuth.access_token(@consumers[endpoint], options) + auth_class = Dropbox::API::Config.auth_type == 'oauth2' ? Dropbox::API::OAuth2 : Dropbox::API::OAuth + @consumers[endpoint] = auth_class.consumer(endpoint) + @tokens[endpoint] = auth_class.access_token(@consumers[endpoint], options) end end diff --git a/lib/dropbox-api/connection/requests.rb b/lib/dropbox-api/connection/requests.rb index 2ae47c1..e071f38 100644 --- a/lib/dropbox-api/connection/requests.rb +++ b/lib/dropbox-api/connection/requests.rb @@ -8,7 +8,7 @@ module Requests def request(options = {}) response = yield raise Dropbox::API::Error::ConnectionFailed if !response - status = response.code.to_i + status = (response.respond_to?(:code) ? response.code : response.status).to_i case status when 400 parsed = MultiJson.decode(response.body) diff --git a/lib/dropbox-api/util/config.rb b/lib/dropbox-api/util/config.rb index e518fd6..0a54845 100644 --- a/lib/dropbox-api/util/config.rb +++ b/lib/dropbox-api/util/config.rb @@ -9,6 +9,7 @@ class << self attr_accessor :app_key attr_accessor :app_secret attr_accessor :mode + attr_accessor :auth_type end self.endpoints = { @@ -20,6 +21,7 @@ class << self self.app_key = nil self.app_secret = nil self.mode = 'sandbox' + self.auth_type = 'oauth' end diff --git a/lib/dropbox-api/util/oauth2.rb b/lib/dropbox-api/util/oauth2.rb new file mode 100644 index 0000000..617a285 --- /dev/null +++ b/lib/dropbox-api/util/oauth2.rb @@ -0,0 +1,28 @@ +module Dropbox + module API + + module OAuth2 + + class << self + + def consumer(endpoint) + if !Dropbox::API::Config.app_key or !Dropbox::API::Config.app_secret + raise Dropbox::API::Error::Config.new("app_key or app_secret not provided") + end + ::OAuth2::Client.new(Dropbox::API::Config.app_key, Dropbox::API::Config.app_secret, + :site => Dropbox::API::Config.endpoints[endpoint], + :authorize_url => "#{Dropbox::API::Config.prefix}/oauth2/authorize", + :token_url => "#{Dropbox::API::Config.prefix}/oauth2/token") + end + + def access_token(konsumer, options = {}) + ::OAuth2::AccessToken.new(konsumer, options[:token], options) + end + + end + + end + + end +end + From e4031e70d0c392a5364fff720a9c27faa4d0904a Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Fri, 23 May 2014 11:29:18 -0700 Subject: [PATCH 02/11] Fix some requests that fail due to arity mismatch between oauth and oauth2 tokens --- lib/dropbox-api/connection/requests.rb | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/lib/dropbox-api/connection/requests.rb b/lib/dropbox-api/connection/requests.rb index e071f38..4c48678 100644 --- a/lib/dropbox-api/connection/requests.rb +++ b/lib/dropbox-api/connection/requests.rb @@ -50,26 +50,42 @@ def request(options = {}) def get_raw(endpoint, path, data = {}, headers = {}) query = Dropbox::API::Util.query(data) request(:raw => true) do - token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers + if token.is_a?(::OAuth2::AccessToken) + token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers: headers + else + token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers + end end end def get(endpoint, path, data = {}, headers = {}) query = Dropbox::API::Util.query(data) request do - token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers + if token.is_a?(::OAuth2::AccessToken) + token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers: headers + else + token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers + end end end def post(endpoint, path, data = {}, headers = {}) request do - token(endpoint).post "#{Dropbox::API::Config.prefix}#{path}", data, headers + if token.is_a?(::OAuth2::AccessToken) + token(endpoint).post "#{Dropbox::API::Config.prefix}#{path}", params: data, headers: headers + else + token(endpoint).post "#{Dropbox::API::Config.prefix}#{path}", data, headers + end end end def put(endpoint, path, data = {}, headers = {}) request do - token(endpoint).put "#{Dropbox::API::Config.prefix}#{path}", data, headers + if token.is_a?(::OAuth2::AccessToken) + token(endpoint).put "#{Dropbox::API::Config.prefix}#{path}", params: data, headers: headers + else + token(endpoint).put "#{Dropbox::API::Config.prefix}#{path}", data, headers + end end end From 803738935553fcc84801612a4fc563abf86b5df0 Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Sat, 20 Sep 2014 12:24:24 -0700 Subject: [PATCH 03/11] Extract prefixed request URLs into a variable to help with code readability --- lib/dropbox-api/connection/requests.rb | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/dropbox-api/connection/requests.rb b/lib/dropbox-api/connection/requests.rb index 4c48678..3320b10 100644 --- a/lib/dropbox-api/connection/requests.rb +++ b/lib/dropbox-api/connection/requests.rb @@ -49,42 +49,46 @@ def request(options = {}) def get_raw(endpoint, path, data = {}, headers = {}) query = Dropbox::API::Util.query(data) + request_url = "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}" request(:raw => true) do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers: headers + token(endpoint).get request_url, headers: headers else - token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers + token(endpoint).get request_url, headers end end end def get(endpoint, path, data = {}, headers = {}) query = Dropbox::API::Util.query(data) + request_url = "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers: headers + token(endpoint).get request_url, headers: headers else - token(endpoint).get "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers + token(endpoint).get request_url, headers end end end def post(endpoint, path, data = {}, headers = {}) + request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).post "#{Dropbox::API::Config.prefix}#{path}", params: data, headers: headers + token(endpoint).post request_url, params: data, headers: headers else - token(endpoint).post "#{Dropbox::API::Config.prefix}#{path}", data, headers + token(endpoint).post request_url, data, headers end end end def put(endpoint, path, data = {}, headers = {}) + request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).put "#{Dropbox::API::Config.prefix}#{path}", params: data, headers: headers + token(endpoint).put request_url, params: data, headers: headers else - token(endpoint).put "#{Dropbox::API::Config.prefix}#{path}", data, headers + token(endpoint).put request_url, data, headers end end end From 13a1055dfbafc47f1c3237cd76ed44ad7aeb3318 Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Sat, 20 Sep 2014 12:26:00 -0700 Subject: [PATCH 04/11] Convert hashes to hashrocket syntax to ensure compatibility with old rubies --- lib/dropbox-api/connection/requests.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dropbox-api/connection/requests.rb b/lib/dropbox-api/connection/requests.rb index 3320b10..1969fd9 100644 --- a/lib/dropbox-api/connection/requests.rb +++ b/lib/dropbox-api/connection/requests.rb @@ -52,7 +52,7 @@ def get_raw(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}" request(:raw => true) do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).get request_url, headers: headers + token(endpoint).get request_url, headers => headers else token(endpoint).get request_url, headers end @@ -64,7 +64,7 @@ def get(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).get request_url, headers: headers + token(endpoint).get request_url, headers => headers else token(endpoint).get request_url, headers end @@ -75,7 +75,7 @@ def post(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).post request_url, params: data, headers: headers + token(endpoint).post request_url, params => data, headers => headers else token(endpoint).post request_url, data, headers end @@ -86,7 +86,7 @@ def put(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).put request_url, params: data, headers: headers + token(endpoint).put request_url, params => data, headers => headers else token(endpoint).put request_url, data, headers end From 5ba7b32549f2d869f1a412f58c66d8f5d35a82cc Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Sat, 20 Sep 2014 13:22:56 -0700 Subject: [PATCH 05/11] Add dropbox:authorize_oauth2 rake task --- lib/dropbox-api/tasks.rb | 29 +++++++++++++++++++++++++++++ lib/dropbox-api/util/oauth2.rb | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/dropbox-api/tasks.rb b/lib/dropbox-api/tasks.rb index 6d16cc3..0f1466f 100644 --- a/lib/dropbox-api/tasks.rb +++ b/lib/dropbox-api/tasks.rb @@ -38,6 +38,35 @@ def self.install puts " client = Dropbox::API::Client.new(:token => '#{access_token.token}', :secret => '#{access_token.secret}')" puts "\n" end + + desc "Authorize wizard for Dropbox API OAuth2" + task :authorize_oauth2 do + require "oauth2" + require "dropbox-api" + require "cgi" + print "Enter dropbox app key: " + consumer_key = $stdin.gets.chomp + print "Enter dropbox app secret: " + consumer_secret = $stdin.gets.chomp + + Dropbox::API::Config.app_key = consumer_key + Dropbox::API::Config.app_secret = consumer_secret + + consumer = ::Dropbox::API::OAuth2.consumer(:authorize) + authorize_uri = consumer.authorize_url(client_id: Dropbox::API::Config.app_key, response_type: 'code') + puts "\nGo to this url and click 'Authorize' to get the token:" + puts authorize_uri + print "\nOnce you authorize the app on Dropbox, paste the code here and press enter:" + code = $stdin.gets.chomp + + access_token = consumer.auth_code.get_token(code) + puts "\nAuthorization complete!:\n\n" + puts " Dropbox::API::Config.app_key = '#{consumer_key}'" + puts " Dropbox::API::Config.app_secret = '#{consumer_secret}'" + puts " client = Dropbox::API::Client.new(:token => '#{access_token.token}')" + puts "\n" + end + end end diff --git a/lib/dropbox-api/util/oauth2.rb b/lib/dropbox-api/util/oauth2.rb index 617a285..c2e1bbe 100644 --- a/lib/dropbox-api/util/oauth2.rb +++ b/lib/dropbox-api/util/oauth2.rb @@ -12,7 +12,7 @@ def consumer(endpoint) ::OAuth2::Client.new(Dropbox::API::Config.app_key, Dropbox::API::Config.app_secret, :site => Dropbox::API::Config.endpoints[endpoint], :authorize_url => "#{Dropbox::API::Config.prefix}/oauth2/authorize", - :token_url => "#{Dropbox::API::Config.prefix}/oauth2/token") + :token_url => "#{Dropbox::API::Config.prefix}/oauth2/token") end def access_token(konsumer, options = {}) From a292157120cab402eb3528c806e37481808bc546 Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Sat, 20 Sep 2014 13:23:19 -0700 Subject: [PATCH 06/11] Update README with OAuth2 instructions --- README.markdown | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/README.markdown b/README.markdown index 3614a7f..8812de1 100644 --- a/README.markdown +++ b/README.markdown @@ -47,6 +47,7 @@ Dropbox::API::Config.app_key = YOUR_APP_KEY Dropbox::API::Config.app_secret = YOUR_APP_SECRET Dropbox::API::Config.mode = "sandbox" # if you have a single-directory app # Dropbox::API::Config.mode = "dropbox" # if your app has access to the whole dropbox +Dropbox::API::Config.auth_type = "oauth" # options are "oauth" or "oauth2" (default is "oauth") ``` Dropbox::API::Client @@ -62,6 +63,8 @@ In order to create a Dropbox::API::Client object, you need to have the configura Second thing you need is to have the user authorize your app using OAuth. Here's a short intro on how to do this: +##### OAuth1 + ```ruby consumer = Dropbox::API::OAuth.consumer(:authorize) request_token = consumer.get_request_token @@ -75,12 +78,27 @@ request_token = OAuth::RequestToken.from_hash(consumer, hash) result = request_token.get_access_token(:oauth_verifier => oauth_token) ``` -Now that you have the oauth token and secret, you can create a new instance of the Dropbox::API::Client, like this: +Now that you have the OAuth1 token and secret, you can create a new instance of the Dropbox::API::Client, like this: ```ruby client = Dropbox::API::Client.new :token => result.token, :secret => result.secret ``` +##### OAuth2 +```ruby +consumer = ::Dropbox::API::OAuth2.consumer(:authorize) +authorize_uri = consumer.authorize_url(client_id: Dropbox::API::Config.app_key, response_type: 'code') +# Here the user goes to Dropbox, authorizes the app and is redirected, when +# they return, extract the &code query string parameter +access_token = consumer.auth_code.get_token(params[:code]) +``` + +Now that you have an authenticated OAuth2 access token, you can create a new instance of the Dropbox::API::Client, like this: + +```ruby +client = Dropbox::API::Client.new :token => access_token.token +``` + Rake-based authorization ------------------------ @@ -94,11 +112,11 @@ require "dropbox-api/tasks" Dropbox::API::Tasks.install ``` -You will notice that you have a new rake task - dropbox:authorize +You will notice that you have two new rake tasks - `dropbox:authorize` and `dropbox:authorize_oauth2` -When you call this Rake task, it will ask you to provide the app key and app secret. Afterwards it will present you with an authorize url on Dropbox. +When you call one of these Rake tasks, it will ask you to provide the app key and app secret. Afterwards it will present you with an authorize url on Dropbox. -Simply go to that url, authorize the app, then press enter in the console. +Simply go to that url, authorize the app, then follow the instructions in the console. The rake task will output valid ruby code which you can use to create a client. From 3a368b0745d05d72f355196acae827bed3476a45 Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Tue, 28 Oct 2014 19:29:27 -0700 Subject: [PATCH 07/11] Fix hash rocket syntax bug --- lib/dropbox-api/connection/requests.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/dropbox-api/connection/requests.rb b/lib/dropbox-api/connection/requests.rb index 1969fd9..75d98d3 100644 --- a/lib/dropbox-api/connection/requests.rb +++ b/lib/dropbox-api/connection/requests.rb @@ -52,7 +52,7 @@ def get_raw(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}" request(:raw => true) do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).get request_url, headers => headers + token(endpoint).get request_url, :headers => headers else token(endpoint).get request_url, headers end @@ -64,7 +64,7 @@ def get(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).get request_url, headers => headers + token(endpoint).get request_url, :headers => headers else token(endpoint).get request_url, headers end @@ -75,7 +75,7 @@ def post(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).post request_url, params => data, headers => headers + token(endpoint).post request_url, :params => data, :headers => headers else token(endpoint).post request_url, data, headers end @@ -86,7 +86,7 @@ def put(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).put request_url, params => data, headers => headers + token(endpoint).put request_url, :params => data, :headers => headers else token(endpoint).put request_url, data, headers end From 31c0c7d5f2e644f0fb5cf704d17ce5397a5c58e2 Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Sat, 27 Jun 2015 12:14:14 -0700 Subject: [PATCH 08/11] Fix a bug with POST and PUT request params and bodies Data should be passed as parameters in the body of the request instead of converting it into query string params. Query string will work for smaller amounts of data, but errors arise when the query string becomes too long. For example this is often the case when requesting deltas using a long cursor string. --- lib/dropbox-api/connection/requests.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/dropbox-api/connection/requests.rb b/lib/dropbox-api/connection/requests.rb index 75d98d3..13f9cdf 100644 --- a/lib/dropbox-api/connection/requests.rb +++ b/lib/dropbox-api/connection/requests.rb @@ -75,7 +75,7 @@ def post(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).post request_url, :params => data, :headers => headers + token(endpoint).post request_url, :body => data, :headers => headers else token(endpoint).post request_url, data, headers end @@ -86,7 +86,7 @@ def put(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).put request_url, :params => data, :headers => headers + token(endpoint).put request_url, :body => data, :headers => headers else token(endpoint).put request_url, data, headers end From f62ac634815725b365fa166b35eb52cc487888f3 Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Sat, 27 Jun 2015 13:36:37 -0700 Subject: [PATCH 09/11] Fix failing tests introduced by inclusion of OAuth2 Some notes: - I had to modify the logic in one Dropbox::API::Client#delta test because in my tests the last item returned by the delta API was actually the `test_dir` itself, not the file within it. I made the test flexible enough to handle either case: "file last" or "dir last". - Added a `type` key to connection.yml to indicate that the token provided is either "oauth2" or "oauth1". When ommitted, "oauth1" is assumed. - Alternatively ENV['AUTH']=oauth2 can be set when running the tests. This will override whatever is specified in connection.yml - I think ideally the spec would run all of the tests twice: once with an OAuth1 token and once with OAuth2, but that's a bit more than I have time for. --- lib/dropbox-api/connection/requests.rb | 8 ++++---- spec/connection.sample.yml | 5 +++-- spec/lib/dropbox-api/client_spec.rb | 8 ++++++-- spec/lib/dropbox-api/connection_spec.rb | 6 +++++- spec/support/config.rb | 10 ++++++++-- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/dropbox-api/connection/requests.rb b/lib/dropbox-api/connection/requests.rb index 9da3df5..9a888e8 100644 --- a/lib/dropbox-api/connection/requests.rb +++ b/lib/dropbox-api/connection/requests.rb @@ -58,7 +58,7 @@ def get_raw(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}" request(:raw => true) do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).get request_url, :headers => headers + token(endpoint).get request_url, :headers => headers, :raise_errors => false else token(endpoint).get request_url, headers end @@ -70,7 +70,7 @@ def get(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).get request_url, :headers => headers + token(endpoint).get request_url, :headers => headers, :raise_errors => false else token(endpoint).get request_url, headers end @@ -81,7 +81,7 @@ def post(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).post request_url, :body => data, :headers => headers + token(endpoint).post request_url, :body => data, :headers => headers, :raise_errors => false else token(endpoint).post request_url, data, headers end @@ -92,7 +92,7 @@ def put(endpoint, path, data = {}, headers = {}) request_url = "#{Dropbox::API::Config.prefix}#{path}" request do if token.is_a?(::OAuth2::AccessToken) - token(endpoint).put request_url, :body => data, :headers => headers + token(endpoint).put request_url, :body => data, :headers => headers, :raise_errors => false else token(endpoint).put request_url, data, headers end diff --git a/spec/connection.sample.yml b/spec/connection.sample.yml index 973d372..d6ecd51 100644 --- a/spec/connection.sample.yml +++ b/spec/connection.sample.yml @@ -1,5 +1,6 @@ app_key: # CONSUMER KEY app_secret: # CONSUMER SECRET token: # ACCESS TOKEN -secret: # ACCESS SECRET -mode: # 'sandbox' or 'dropbox' \ No newline at end of file +secret: # ACCESS SECRET (for oauth1 only) +mode: # 'sandbox' or 'dropbox' +type: # 'oauth2' or 'oauth' (default) \ No newline at end of file diff --git a/spec/lib/dropbox-api/client_spec.rb b/spec/lib/dropbox-api/client_spec.rb index 0f13d37..5ab1997 100644 --- a/spec/lib/dropbox-api/client_spec.rb +++ b/spec/lib/dropbox-api/client_spec.rb @@ -222,8 +222,12 @@ @client.upload delete_filename, 'Some file' response = @client.delta cursor, files = response.cursor, response.entries - files.last.path.should == delete_filename - files.last.destroy + delta_file = files.last + if delta_file.path == Dropbox::Spec.test_dir + delta_file = files.at(-2) + end + delta_file.path.should == delete_filename + delta_file.destroy @client.upload filename, 'Another file' response = @client.delta(cursor) cursor, files = response.cursor, response.entries diff --git a/spec/lib/dropbox-api/connection_spec.rb b/spec/lib/dropbox-api/connection_spec.rb index c6df89c..c9cdb75 100644 --- a/spec/lib/dropbox-api/connection_spec.rb +++ b/spec/lib/dropbox-api/connection_spec.rb @@ -112,7 +112,11 @@ describe "#consumer" do it "returns an appropriate consumer object" do - @connection.consumer(:main).should be_a(::OAuth::Consumer) + if Dropbox::API::Config.auth_type == 'oauth2' + @connection.consumer(:main).should be_a(::OAuth2::Client) + else + @connection.consumer(:main).should be_a(::OAuth::Consumer) + end end end diff --git a/spec/support/config.rb b/spec/support/config.rb index 76f0cff..b29fb07 100644 --- a/spec/support/config.rb +++ b/spec/support/config.rb @@ -1,4 +1,5 @@ require "yaml" +require "oauth2" config = YAML.load_file "spec/connection.yml" @@ -6,8 +7,13 @@ Dropbox::API::Config.app_secret = config['app_secret'] Dropbox::API::Config.mode = config['mode'] -Dropbox::Spec.token = config['token'] -Dropbox::Spec.secret = config['secret'] +if ENV['AUTH'] == 'oauth2' || config['type'] == 'oauth2' + Dropbox::API::Config.auth_type = "oauth2" + Dropbox::Spec.token = config['token'] +else + Dropbox::Spec.token = config['token'] + Dropbox::Spec.secret = config['secret'] +end Dropbox::Spec.namespace = Time.now.to_i Dropbox::Spec.instance = Dropbox::API::Client.new(:token => Dropbox::Spec.token, From a11a35477aa06cc8cc4bd4447fe53cbeddd9a7f7 Mon Sep 17 00:00:00 2001 From: Michael Lawlor Date: Tue, 7 Jul 2015 11:06:32 -0700 Subject: [PATCH 10/11] Use a separate :main consumer for fetching the access token from Dropbox during token exchange --- README.markdown | 1 + lib/dropbox-api/tasks.rb | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index f0e4012..2fafc81 100644 --- a/README.markdown +++ b/README.markdown @@ -92,6 +92,7 @@ consumer = ::Dropbox::API::OAuth2.consumer(:authorize) authorize_uri = consumer.authorize_url(client_id: Dropbox::API::Config.app_key, response_type: 'code') # Here the user goes to Dropbox, authorizes the app and is redirected, when # they return, extract the &code query string parameter +consumer = ::Dropbox::API::OAuth2.consumer(:main) access_token = consumer.auth_code.get_token(params[:code]) ``` diff --git a/lib/dropbox-api/tasks.rb b/lib/dropbox-api/tasks.rb index 0f1466f..7c1e7a0 100644 --- a/lib/dropbox-api/tasks.rb +++ b/lib/dropbox-api/tasks.rb @@ -52,14 +52,15 @@ def self.install Dropbox::API::Config.app_key = consumer_key Dropbox::API::Config.app_secret = consumer_secret - consumer = ::Dropbox::API::OAuth2.consumer(:authorize) - authorize_uri = consumer.authorize_url(client_id: Dropbox::API::Config.app_key, response_type: 'code') + auth_consumer = ::Dropbox::API::OAuth2.consumer(:authorize) + authorize_uri = auth_consumer.authorize_url(client_id: Dropbox::API::Config.app_key, response_type: 'code') puts "\nGo to this url and click 'Authorize' to get the token:" puts authorize_uri print "\nOnce you authorize the app on Dropbox, paste the code here and press enter:" code = $stdin.gets.chomp - access_token = consumer.auth_code.get_token(code) + main_consumer = ::Dropbox::API::OAuth2.consumer(:main) + access_token = main_consumer.auth_code.get_token(code) puts "\nAuthorization complete!:\n\n" puts " Dropbox::API::Config.app_key = '#{consumer_key}'" puts " Dropbox::API::Config.app_secret = '#{consumer_secret}'" From 7fb07e54e3d07e19c9a9ad1e75a2f56bb067c3e6 Mon Sep 17 00:00:00 2001 From: Jonathan Allard Date: Tue, 7 Jul 2015 20:25:58 -0400 Subject: [PATCH 11/11] OAuth2 Flow WIP --- lib/dropbox-api/tasks.rb | 8 ++++---- lib/dropbox-api/util/oauth2.rb | 17 +++++++++++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/dropbox-api/tasks.rb b/lib/dropbox-api/tasks.rb index 7c1e7a0..9ccf5af 100644 --- a/lib/dropbox-api/tasks.rb +++ b/lib/dropbox-api/tasks.rb @@ -52,15 +52,15 @@ def self.install Dropbox::API::Config.app_key = consumer_key Dropbox::API::Config.app_secret = consumer_secret - auth_consumer = ::Dropbox::API::OAuth2.consumer(:authorize) - authorize_uri = auth_consumer.authorize_url(client_id: Dropbox::API::Config.app_key, response_type: 'code') + authorize_uri = ::Dropbox::API::OAuth2::AuthFlow.start + puts "\nGo to this url and click 'Authorize' to get the token:" puts authorize_uri print "\nOnce you authorize the app on Dropbox, paste the code here and press enter:" code = $stdin.gets.chomp - main_consumer = ::Dropbox::API::OAuth2.consumer(:main) - access_token = main_consumer.auth_code.get_token(code) + access_token = ::Dropbox::API::OAuth2::AuthFlow.finish(code) + puts "\nAuthorization complete!:\n\n" puts " Dropbox::API::Config.app_key = '#{consumer_key}'" puts " Dropbox::API::Config.app_secret = '#{consumer_secret}'" diff --git a/lib/dropbox-api/util/oauth2.rb b/lib/dropbox-api/util/oauth2.rb index c2e1bbe..e7727ed 100644 --- a/lib/dropbox-api/util/oauth2.rb +++ b/lib/dropbox-api/util/oauth2.rb @@ -1,10 +1,8 @@ module Dropbox module API - module OAuth2 class << self - def consumer(endpoint) if !Dropbox::API::Config.app_key or !Dropbox::API::Config.app_secret raise Dropbox::API::Error::Config.new("app_key or app_secret not provided") @@ -18,11 +16,22 @@ def consumer(endpoint) def access_token(konsumer, options = {}) ::OAuth2::AccessToken.new(konsumer, options[:token], options) end - end - end + module AuthFlow + def self.start + OAuth2.consumer(:authorize).authorize_url({ + client_id: Dropbox::API::Config.app_key, + response_type: 'code' + }) + end + # Exchanges code for a token + def self.finish(code) + OAuth2.consumer(:main).auth_code.get_token(code) + end + end + end end end