From c3fb49ee47bf26679e6b5d2b3bcf044ff9bd2225 Mon Sep 17 00:00:00 2001 From: ifedapoolarewaju Date: Sat, 14 Sep 2019 13:55:30 +0100 Subject: [PATCH 1/3] companion,companion-client,provider-views: revoke provider access on logout --- .../@uppy/companion-client/src/Provider.js | 4 +-- .../src/server/controllers/logout.js | 32 ++++++++++++------- .../src/server/provider/drive/index.js | 14 ++++++++ .../src/server/provider/dropbox/index.js | 15 +++++++++ .../src/server/provider/facebook/index.js | 14 ++++++++ .../src/server/provider/instagram/index.js | 5 +++ packages/@uppy/core/src/index.js | 1 + packages/@uppy/provider-views/src/index.js | 10 +++++- 8 files changed, 81 insertions(+), 14 deletions(-) diff --git a/packages/@uppy/companion-client/src/Provider.js b/packages/@uppy/companion-client/src/Provider.js index d575a6a4cd..138f6975e3 100644 --- a/packages/@uppy/companion-client/src/Provider.js +++ b/packages/@uppy/companion-client/src/Provider.js @@ -58,9 +58,9 @@ module.exports = class Provider extends RequestClient { return this.get(`${this.id}/list/${directory || ''}`) } - logout (redirect = location.href) { + logout () { return new Promise((resolve, reject) => { - this.get(`${this.id}/logout?redirect=${redirect}`) + this.get(`${this.id}/logout`) .then((res) => { this.uppy.getPlugin(this.pluginId).storage.removeItem(this.tokenKey) .then(() => resolve(res)) diff --git a/packages/@uppy/companion/src/server/controllers/logout.js b/packages/@uppy/companion/src/server/controllers/logout.js index f5b1c696a1..3155827f37 100644 --- a/packages/@uppy/companion/src/server/controllers/logout.js +++ b/packages/@uppy/companion/src/server/controllers/logout.js @@ -5,20 +5,30 @@ const tokenService = require('../helpers/jwt') * @param {object} req * @param {object} res */ -function logout (req, res) { - const session = req.session - const providerName = req.params.providerName - - if (req.uppy.providerTokens && req.uppy.providerTokens[providerName]) { - delete req.uppy.providerTokens[providerName] - tokenService.removeFromCookies(res, req.uppy.options, req.uppy.provider.authProviderName) +function logout (req, res, next) { + const cleanSession = () => { + if (req.session.grant) { + req.session.grant.state = null + req.session.grant.dynamic = null + } } + const providerName = req.params.providerName + const token = req.uppy.providerTokens ? req.uppy.providerTokens[providerName] : null + if (token) { + req.uppy.provider.logout({ token }, (err, data) => { + if (err) { + return next(err) + } - if (session.grant) { - session.grant.state = null - session.grant.dynamic = null + delete req.uppy.providerTokens[providerName] + tokenService.removeFromCookies(res, req.uppy.options, req.uppy.provider.authProviderName) + cleanSession() + res.json(Object.assign({ ok: true }, data)) + }) + } else { + cleanSession() + res.json({ ok: true, revoked: false }) } - res.json({ ok: true }) } module.exports = logout diff --git a/packages/@uppy/companion/src/server/provider/drive/index.js b/packages/@uppy/companion/src/server/provider/drive/index.js index 19c1c7a696..635c2b0afc 100644 --- a/packages/@uppy/companion/src/server/provider/drive/index.js +++ b/packages/@uppy/companion/src/server/provider/drive/index.js @@ -133,6 +133,20 @@ class Drive { }) } + logout ({ token }, done) { + return this.client + .get('https://accounts.google.com/o/oauth2/revoke') + .qs({ token }) + .request((err, resp) => { + if (err || resp.statusCode !== 200) { + logger.error(err, 'provider.drive.logout.error') + done(this._error(err, resp)) + return + } + done(null, { revoked: true }) + }) + } + adaptData (res, teamDrivesResp, uppy, directory, query) { const adaptItem = (item) => ({ isFolder: adapter.isFolder(item), diff --git a/packages/@uppy/companion/src/server/provider/dropbox/index.js b/packages/@uppy/companion/src/server/provider/dropbox/index.js index a6c73db3d7..a31c3f740c 100644 --- a/packages/@uppy/companion/src/server/provider/dropbox/index.js +++ b/packages/@uppy/companion/src/server/provider/dropbox/index.js @@ -160,6 +160,21 @@ class DropBox { }) } + logout ({ token }, done) { + return this.client + .post('auth/token/revoke') + .options({ version: '2' }) + .auth(token) + .request((err, resp) => { + if (err || resp.statusCode !== 200) { + logger.error(err, 'provider.dropbox.size.error') + done(this._error(err, resp)) + return + } + done(null, { revoked: true }) + }) + } + adaptData (res, uppy) { const data = { username: adapter.getUsername(res), items: [] } const items = adapter.getItemSubList(res) diff --git a/packages/@uppy/companion/src/server/provider/facebook/index.js b/packages/@uppy/companion/src/server/provider/facebook/index.js index 6bd5026e92..d5226b25cd 100644 --- a/packages/@uppy/companion/src/server/provider/facebook/index.js +++ b/packages/@uppy/companion/src/server/provider/facebook/index.js @@ -112,6 +112,20 @@ class Facebook { }) } + logout ({ token }, done) { + return this.client + .delete('me/permissions') + .auth(token) + .request((err, resp) => { + if (err || resp.statusCode !== 200) { + logger.error(err, 'provider.facebook.logout.error') + done(this._error(err, resp)) + return + } + done(null, { revoked: true }) + }) + } + adaptData (res, username, directory, currentQuery) { const data = { username: username, items: [] } const items = adapter.getItemSubList(res) diff --git a/packages/@uppy/companion/src/server/provider/instagram/index.js b/packages/@uppy/companion/src/server/provider/instagram/index.js index ccbc94431d..a5865e3441 100644 --- a/packages/@uppy/companion/src/server/provider/instagram/index.js +++ b/packages/@uppy/companion/src/server/provider/instagram/index.js @@ -108,6 +108,11 @@ class Instagram { }) } + logout (_, done) { + // access revoke is not supported by Instagram's API + done(null, { revoked: false, manual_revoke_url: 'https://www.instagram.com/accounts/manage_access/' }) + } + adaptData (res, username) { const data = { username: username, items: [] } const items = adapter.getItemSubList(res) diff --git a/packages/@uppy/core/src/index.js b/packages/@uppy/core/src/index.js index ece5c08f8f..c15a2221ba 100644 --- a/packages/@uppy/core/src/index.js +++ b/packages/@uppy/core/src/index.js @@ -49,6 +49,7 @@ class Uppy { youCanOnlyUploadFileTypes: 'You can only upload: %{types}', companionError: 'Connection with Companion failed', companionAuthError: 'Authorization required', + companionUnauthorizeHint: 'To unauthorize to your %{provider} account, please go to %{url}', failedToUpload: 'Failed to upload %{file}', noInternetConnection: 'No Internet connection', connectedToInternet: 'Connected to the Internet', diff --git a/packages/@uppy/provider-views/src/index.js b/packages/@uppy/provider-views/src/index.js index dec9cc9464..8c1c744515 100644 --- a/packages/@uppy/provider-views/src/index.js +++ b/packages/@uppy/provider-views/src/index.js @@ -200,9 +200,17 @@ module.exports = class ProviderView { * Removes session token on client side. */ logout () { - this.provider.logout(location.href) + this.provider.logout() .then((res) => { if (res.ok) { + if (!res.revoked) { + const message = this.plugin.uppy.i18n('companionUnauthorizeHint', { + provider: this.plugin.title, + url: res.manual_revoke_url + }) + this.plugin.uppy.info(message) + } + const newState = { authenticated: false, files: [], From b73d461bf814bdfddf8709713ccd8a482a90125a Mon Sep 17 00:00:00 2001 From: ifedapoolarewaju Date: Fri, 20 Sep 2019 11:51:15 +0100 Subject: [PATCH 2/3] companion: logout / revoke support for OneDrive --- .../@uppy/companion/src/server/provider/onedrive/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/@uppy/companion/src/server/provider/onedrive/index.js b/packages/@uppy/companion/src/server/provider/onedrive/index.js index d7bed25f08..4bfa265401 100644 --- a/packages/@uppy/companion/src/server/provider/onedrive/index.js +++ b/packages/@uppy/companion/src/server/provider/onedrive/index.js @@ -91,6 +91,11 @@ class OneDrive { }) } + logout (_, done) { + // access revoke is not supported by Microsoft/OneDrive's API + done(null, { revoked: false, manual_revoke_url: 'https://account.live.com/consent/Manage' }) + } + adaptData (res, username) { const data = { username, items: [] } const items = adapter.getItemSubList(res) From fae6cb62075315c575db767c5541ae30007f75bd Mon Sep 17 00:00:00 2001 From: ifedapoolarewaju Date: Wed, 25 Sep 2019 14:23:56 +0100 Subject: [PATCH 3/3] provider-views: display logout hint for a while longer --- packages/@uppy/provider-views/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@uppy/provider-views/src/index.js b/packages/@uppy/provider-views/src/index.js index 8c1c744515..63a644bde9 100644 --- a/packages/@uppy/provider-views/src/index.js +++ b/packages/@uppy/provider-views/src/index.js @@ -208,7 +208,7 @@ module.exports = class ProviderView { provider: this.plugin.title, url: res.manual_revoke_url }) - this.plugin.uppy.info(message) + this.plugin.uppy.info(message, 'info', 7000) } const newState = {