Forráskód Böngészése

Merge pull request #1843 from transloadit/revoke-provider-access

Revoke provider access
Ifedapo .A. Olarewaju 5 éve
szülő
commit
1dd4d79aa7

+ 2 - 2
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))

+ 21 - 11
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

+ 14 - 0
packages/@uppy/companion/src/server/provider/drive/index.js

@@ -134,6 +134,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, sharedDrivesResp, uppy, directory, query) {
     const adaptItem = (item) => ({
       isFolder: adapter.isFolder(item),

+ 15 - 0
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)

+ 14 - 0
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)

+ 5 - 0
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)

+ 5 - 0
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)

+ 1 - 0
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',

+ 9 - 1
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, 'info', 7000)
+          }
+
           const newState = {
             authenticated: false,
             files: [],