web_file_browser.rb in dropbox-sdk-1.5.1 vs web_file_browser.rb in dropbox-sdk-1.6
- old
+ new
@@ -11,108 +11,105 @@
# -------------------------------------------------------------------
require 'rubygems'
require 'sinatra'
require 'pp'
+require 'securerandom'
require './lib/dropbox_sdk'
# Get your app's key and secret from https://www.dropbox.com/developers/
APP_KEY = ''
APP_SECRET = ''
-ACCESS_TYPE = :app_folder #The two valid values here are :app_folder and :dropbox
- #The default is :app_folder, but your application might be
- #set to have full :dropbox access. Check your app at
- #https://www.dropbox.com/developers/apps
# -------------------------------------------------------------------
# OAuth stuff
-get '/oauth-start' do
- # OAuth Step 1: Get a request token from Dropbox.
- db_session = DropboxSession.new(APP_KEY, APP_SECRET)
- begin
- db_session.get_request_token
- rescue DropboxError => e
- return html_page "Exception in OAuth step 1", "<p>#{h e}</p>"
- end
+def get_web_auth()
+ return DropboxOAuth2Flow.new(APP_KEY, APP_SECRET, url('/dropbox-auth-finish'),
+ session, :dropbox_auth_csrf_token)
+end
- session[:request_db_session] = db_session.serialize
+get '/dropbox-auth-start' do
+ authorize_url = get_web_auth().start()
- # OAuth Step 2: Send the user to the Dropbox website so they can authorize
- # our app. After the user authorizes our app, Dropbox will redirect them
- # to our '/oauth-callback' endpoint.
- auth_url = db_session.get_authorize_url url('/oauth-callback')
- redirect auth_url
+ # Send the user to the Dropbox website so they can authorize our app. After the user
+ # authorizes our app, Dropbox will redirect them to our '/dropbox-auth-finish' endpoint.
+ redirect authorize_url
end
-get '/oauth-callback' do
- # Finish OAuth Step 2
- ser = session[:request_db_session]
- unless ser
- return html_page "Error in OAuth step 2", "<p>Couldn't find OAuth state in session.</p>"
- end
- db_session = DropboxSession.deserialize(ser)
-
- # OAuth Step 3: Get an access token from Dropbox.
+get '/dropbox-auth-finish' do
begin
- db_session.get_access_token
+ access_token, user_id, url_state = get_web_auth.finish(params)
+ rescue DropboxOAuth2Flow::BadRequestError => e
+ return html_page "Error in OAuth 2 flow", "<p>Bad request to /dropbox-auth-finish: #{e}</p>"
+ rescue DropboxOAuth2Flow::BadStateError => e
+ return html_page "Error in OAuth 2 flow", "<p>Auth session expired: #{e}</p>"
+ rescue DropboxOAuth2Flow::CsrfError => e
+ logger.info("/dropbox-auth-finish: CSRF mismatch: #{e}")
+ return html_page "Error in OAuth 2 flow", "<p>CSRF mismatch</p>"
+ rescue DropboxOAuth2Flow::NotApprovedError => e
+ return html_page "Not Approved?", "<p>Why not, bro?</p>"
+ rescue DropboxOAuth2Flow::ProviderError => e
+ return html_page "Error in OAuth 2 flow", "Error redirect from Dropbox: #{e}"
rescue DropboxError => e
- return html_page "Exception in OAuth step 3", "<p>#{h e}</p>"
+ logger.info "Error getting OAuth 2 access token: #{e}"
+ return html_page "Error in OAuth 2 flow", "<p>Error getting access token</p>"
end
- session.delete(:request_db_session)
- session[:authorized_db_session] = db_session.serialize
+
+ # In this simple example, we store the authorized DropboxSession in the session.
+ # A real webapp might store it somewhere more persistent.
+ session[:access_token] = access_token
redirect url('/')
- # In this simple example, we store the authorized DropboxSession in the web
- # session hash. A "real" webapp might store it somewhere more persistent.
end
+get '/dropbox-unlink' do
+ session.delete(:access_token)
+ nil
+end
+
# If we already have an authorized DropboxSession, returns a DropboxClient.
-def get_db_client
- if session[:authorized_db_session]
- db_session = DropboxSession.deserialize(session[:authorized_db_session])
- begin
- return DropboxClient.new(db_session, ACCESS_TYPE)
- rescue DropboxAuthError => e
- # The stored session didn't work. Fall through and start OAuth.
- session[:authorized_db_session].delete
- end
+def get_dropbox_client
+ if session[:access_token]
+ return DropboxClient.new(session[:access_token])
end
end
# -------------------------------------------------------------------
# File/folder display stuff
get '/' do
# Get the DropboxClient object. Redirect to OAuth flow if necessary.
- db_client = get_db_client
- unless db_client
- redirect url("/oauth-start")
+ client = get_dropbox_client
+ unless client
+ redirect url("/dropbox-auth-start")
end
# Call DropboxClient.metadata
path = params[:path] || '/'
begin
- entry = db_client.metadata(path)
+ entry = client.metadata(path)
rescue DropboxAuthError => e
- session.delete(:authorized_db_session) # An auth error means the db_session is probably bad
- return html_page "Dropbox auth error", "<p>#{h e}</p>"
+ session.delete(:access_token) # An auth error means the access token is probably bad
+ logger.info "Dropbox auth error: #{e}"
+ return html_page "Dropbox auth error"
rescue DropboxError => e
if e.http_response.code == '404'
- return html_page "Path not found: #{h path}", ""
+ return html_page "Path not found: #{h path}"
else
- return html_page "Dropbox API error", "<pre>#{h e.http_response}</pre>"
+ logger.info "Dropbox API error: #{e}"
+ return html_page "Dropbox API error"
end
end
if entry['is_dir']
- render_folder(db_client, entry)
+ render_folder(client, entry)
else
- render_file(db_client, entry)
+ render_file(client, entry)
end
end
-def render_folder(db_client, entry)
+def render_folder(client, entry)
# Provide an upload form (so the user can add files to this folder)
out = "<form action='/upload' method='post' enctype='multipart/form-data'>"
out += "<label for='file'>Upload file:</label> <input name='file' type='file'/>"
out += "<input type='submit' value='Upload'/>"
out += "<input name='folder' type='hidden' value='#{h entry['path']}'/>"
@@ -126,11 +123,11 @@
end
html_page "Folder: #{entry['path']}", out
end
-def render_file(db_client, entry)
+def render_file(client, entry)
# Just dump out metadata hash
html_page "File: #{entry['path']}", "<pre>#{h entry.pretty_inspect}</pre>"
end
# -------------------------------------------------------------------
@@ -142,36 +139,43 @@
unless file && (temp_file = file[:tempfile]) && (name = file[:filename])
return html_page "Upload error", "<p>No file selected.</p>"
end
# Get the DropboxClient object.
- db_client = get_db_client
- unless db_client
+ client = get_dropbox_client
+ unless client
return html_page "Upload error", "<p>Not linked with a Dropbox account.</p>"
end
# Call DropboxClient.put_file
begin
- entry = db_client.put_file("#{params[:folder]}/#{name}", temp_file.read)
+ entry = client.put_file("#{params[:folder]}/#{name}", temp_file.read)
rescue DropboxAuthError => e
- session.delete(:authorized_db_session) # An auth error means the db_session is probably bad
- return html_page "Dropbox auth error", "<p>#{h e}</p>"
+ session.delete(:access_token) # An auth error means the access token is probably bad
+ logger.info "Dropbox auth error: #{e}"
+ return html_page "Dropbox auth error"
rescue DropboxError => e
- return html_page "Dropbox API error", "<p>#{h e}</p>"
+ logger.info "Dropbox API error: #{e}"
+ return html_page "Dropbox API error"
end
html_page "Upload complete", "<pre>#{h entry.pretty_inspect}</pre>"
end
# -------------------------------------------------------------------
-def html_page(title, body)
+def html_page(title, body='')
"<html>" +
"<head><title>#{h title}</title></head>" +
"<body><h1>#{h title}</h1>#{body}</body>" +
"</html>"
end
+# Rack will issue a warning if no session secret key is set. A real web app would not have
+# a hard-coded secret in the code but would load it from a config file.
+use Rack::Session::Cookie, :secret => 'dummy_secret'
+
+set :port, 5000
enable :sessions
helpers do
include Rack::Utils
alias_method :h, :escape_html