send authtoken via query param

This commit is contained in:
Ifedapo Olarewaju 2019-02-17 21:09:20 +01:00
parent eabf6f6576
commit e8813a8b33
7 changed files with 79 additions and 59 deletions

View file

@ -1,11 +1,7 @@
/**
* oAuth callback. Encrypts the access token and sends the new token with the response,
* and redirects to redirect url.
*/
const tokenService = require('../helpers/jwt')
const parseUrl = require('url').parse
const { hasMatch, sanitizeHtml } = require('../helpers/utils')
const oAuthState = require('../helpers/oauth-state')
const logger = require('../logger')
/**
@ -25,43 +21,5 @@ module.exports = function callback (req, res, next) {
req.uppy.providerTokens[providerName] = req.query.access_token
logger.debug(`Generating auth token for provider ${providerName}.`)
const uppyAuthToken = tokenService.generateToken(req.uppy.providerTokens, req.uppy.options.secret)
// add the token to cookies for thumbnail/image requests
tokenService.addToCookies(res, uppyAuthToken, req.uppy.options)
const state = (req.session.grant || {}).state
if (state) {
const origin = oAuthState.getFromState(state, 'origin', req.uppy.options.secret)
const allowedClients = req.uppy.options.clients
// if no preset clients then allow any client
if (!allowedClients || hasMatch(origin, allowedClients) || hasMatch(parseUrl(origin).host, allowedClients)) {
const redirect = oAuthState.getFromState(state, 'redirect', req.uppy.options.secret)
if (redirect) {
// if a redirect value is specified from the client, then redirect there instead
const query = (parseUrl(redirect).query ? `&` : `?`) + `uppyAuthToken=${uppyAuthToken}`
return res.redirect(`${redirect}${query}`)
}
return res.send(htmlContent(uppyAuthToken, origin))
}
}
next()
}
/**
*
* @param {string} token uppy auth token
* @param {string} origin url string
*/
const htmlContent = (token, origin) => {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script>
window.opener.postMessage({token: "${token}"}, "${sanitizeHtml(origin)}")
window.close()
</script>
</head>
<body></body>
</html>`
return res.redirect(req.uppy.buildURL(`/${providerName}/send-token?uppyAuthToken=${uppyAuthToken}`, true))
}

View file

@ -1,6 +1,7 @@
module.exports = {
authorized: require('./authorized'),
callback: require('./callback'),
sendToken: require('./send-token'),
get: require('./get'),
thumbnail: require('./thumbnail'),
list: require('./list'),

View file

@ -0,0 +1,51 @@
/**
*
* sends auth token to uppy client
*/
const tokenService = require('../helpers/jwt')
const parseUrl = require('url').parse
const { hasMatch, sanitizeHtml } = require('../helpers/utils')
const oAuthState = require('../helpers/oauth-state')
/**
*
* @param {object} req
* @param {object} res
* @param {function} next
*/
module.exports = function sendToken (req, res, next) {
const uppyAuthToken = req.uppy.authToken
// add the token to cookies for thumbnail/image requests
tokenService.addToCookies(res, uppyAuthToken, req.uppy.options)
const state = (req.session.grant || {}).state
if (state) {
const origin = oAuthState.getFromState(state, 'origin', req.uppy.options.secret)
const allowedClients = req.uppy.options.clients
// if no preset clients then allow any client
if (!allowedClients || hasMatch(origin, allowedClients) || hasMatch(parseUrl(origin).host, allowedClients)) {
return res.send(htmlContent(uppyAuthToken, origin))
}
}
next()
}
/**
*
* @param {string} token uppy auth token
* @param {string} origin url string
*/
const htmlContent = (token, origin) => {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script>
window.opener.postMessage({token: "${token}"}, "${sanitizeHtml(origin)}")
window.close()
</script>
</head>
<body></body>
</html>`
}

View file

@ -87,6 +87,7 @@ module.exports.app = (options = {}) => {
app.get('/:providerName/redirect', middlewares.hasSessionAndProvider, controllers.redirect)
app.get('/:providerName/logout', middlewares.hasSessionAndProvider, middlewares.gentleVerifyToken, controllers.logout)
app.get('/:providerName/authorized', middlewares.hasSessionAndProvider, middlewares.gentleVerifyToken, controllers.authorized)
app.get('/:providerName/send-token', middlewares.hasSessionAndProvider, middlewares.verifyToken, controllers.sendToken)
app.get('/:providerName/list/:id?', middlewares.hasSessionAndProvider, middlewares.verifyToken, controllers.list)
app.post('/:providerName/get/:id', middlewares.hasSessionAndProvider, middlewares.verifyToken, controllers.get)
app.get('/:providerName/thumbnail/:id', middlewares.hasSessionAndProvider, middlewares.cookieAuthToken, middlewares.verifyToken, controllers.thumbnail)
@ -217,7 +218,7 @@ const getOptionsMiddleware = (options) => {
req.uppy = {
options,
s3Client,
authToken: req.header('uppy-auth-token'),
authToken: req.header('uppy-auth-token') || req.query.uppyAuthToken,
buildURL: getURLBuilder(options)
}
next()

View file

@ -66,26 +66,35 @@ describe('download provdier file', () => {
})
describe('test authentication', () => {
test('authentication callback redirects to specified url', () => {
test('authentication callback redirects to send-token url', () => {
return request(authServer)
.get('/drive/callback')
.set('uppy-auth-token', token)
.expect(302)
.expect((res) => {
expect(res.header['location']).toContain('http://localhost:3020/drive/send-token?uppyAuthToken=')
})
})
test('the token gets sent via cookie and html', () => {
return request(authServer)
.get(`/drive/send-token?uppyAuthToken=${token}`)
.expect(200)
.expect((res) => {
const authToken = res.header['set-cookie'][0].split(';')[0].split('uppyAuthToken=')[1]
expect(authToken).toEqual(token)
// see mock ../../src/server/helpers/oauth-state above for http://localhost:3020
const body = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script>
window.opener.postMessage({token: "${authToken}"}, "http://localhost:3020")
window.close()
</script>
</head>
<body></body>
</html>`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script>
window.opener.postMessage({token: "${token}"}, "http://localhost:3020")
window.close()
</script>
</head>
<body></body>
</html>`
expect(res.text).toBe(body)
})
})

View file

@ -5,7 +5,7 @@ const session = require('express-session')
var authServer = express()
authServer.use(session({ secret: 'grant', resave: true, saveUninitialized: true }))
authServer.all('/drive/callback', (req, res, next) => {
authServer.all('/drive/send-token', (req, res, next) => {
req.session.grant = {
state: 'non-empty-value' }
next()

View file

@ -422,7 +422,7 @@ module.exports = class ProviderView {
}
handleAuth () {
const authState = btoa(JSON.stringify({ origin: location.origin }))
const authState = btoa(JSON.stringify({ origin: location.origin, redirect: 'http://localhost:3' }))
const link = `${this.provider.authUrl()}?state=${authState}`
const authWindow = window.open(link, '_blank')