nebulab-dropbox
Version:
Client library for the Dropbox API
93 lines (82 loc) • 3.31 kB
text/coffeescript
# OAuth driver that redirects the browser to a node app to complete the flow.
#
# This is useful for testing node.js libraries and applications.
class Dropbox.AuthDriver.NodeServer
# Starts up the node app that intercepts the browser redirect.
#
# @param {Object} options (optional) one or more of the options below
# @option options {Number} port the number of the TCP port that will receive
# HTTPS requests; defaults to 8912
# @option options {Object} tls one or more of the options accepted by
# tls.createServer in the node.js standard library; at a minimum, the key
# option should be provided
constructor: (options) ->
@_port = options?.port or 8912
if options?.tls
@_tlsOptions = options.tls
if typeof @_tlsOptions is 'string' or @_tlsOptions instanceof Buffer
@_tlsOptions = key: @_tlsOptions, cert: @_tlsOptions
else
@_tlsOptions = null
# Calling require in the constructor because this doesn't work in browsers.
@_fs = Dropbox.Env.require 'fs'
@_http = Dropbox.Env.require 'http'
@_https = Dropbox.Env.require 'https'
@_open = Dropbox.Env.require 'open'
@_callbacks = {}
@_nodeUrl = Dropbox.Env.require 'url'
@createApp()
# The /authorize response type.
authType: -> "code"
# URL to the node.js OAuth callback handler.
url: ->
protocol = if @_tlsOptions is null then 'http' else 'https'
"#{protocol}://localhost:#{@_port}/oauth_callback"
# Opens the token
doAuthorize: (authUrl, stateParam, client, callback) ->
@_callbacks[stateParam] = callback
@openBrowser authUrl
# Opens the given URL in a browser.
openBrowser: (url) ->
unless url.match /^https?:\/\//
throw new Error("Not a http/https URL: #{url}")
if 'BROWSER' of process.env
@_open url, process.env['BROWSER']
else
@_open url
# Creates and starts up an HTTP server that will intercept the redirect.
createApp: ->
if @_tlsOptions
@_app = @_https.createServer @_tlsOptions, (request, response) =>
@doRequest request, response
else
@_app = @_http.createServer (request, response) =>
@doRequest request, response
@_app.listen @_port
# Shuts down the HTTP server.
#
# The driver will become unusable after this call.
closeServer: ->
@_app.close()
# Reads out an /authorize callback.
doRequest: (request, response) ->
url = @_nodeUrl.parse request.url, true
if url.pathname is '/oauth_callback'
stateParam = url.query.state
if @_callbacks[stateParam]
@_callbacks[stateParam](url.query)
delete @_callbacks[stateParam]
data = ''
request.on 'data', (dataFragment) -> data += dataFragment
request.on 'end', => @closeBrowser response
# Renders a response that will close the browser window used for OAuth.
closeBrowser: (response) ->
closeHtml = """
<!doctype html>
<script type="text/javascript">window.close();</script>
<p>Please close this window.</p>
"""
response.writeHead(200,
'Content-Length': closeHtml.length, 'Content-Type': 'text/html')
response.write closeHtml
response.end()