Jelajahi Sumber

companion: send 401 for invalid access token

Ifedapo Olarewaju 6 tahun lalu
induk
melakukan
6fb6138321

+ 6 - 2
packages/@uppy/companion/src/server/controllers/get.js

@@ -2,7 +2,7 @@ const Uploader = require('../Uploader')
 const redis = require('../redis')
 const logger = require('../logger')
 
-function get (req, res) {
+function get (req, res, next) {
   const providerName = req.params.providerName
   const id = req.params.id
   const body = req.body
@@ -11,7 +11,11 @@ function get (req, res) {
   const { providerOptions } = req.uppy.options
 
   // get the file size before proceeding
-  provider.size({ id, token }, (size) => {
+  provider.size({ id, token }, (err, size) => {
+    if (err) {
+      return err.isAuthError ? res.sendStatus(401) : next(err)
+    }
+
     if (!size) {
       logger.error('unable to determine file size', 'controller.get.provider.size')
       return res.status(400).json({error: 'unable to determine file size'})

+ 4 - 1
packages/@uppy/companion/src/server/controllers/list.js

@@ -3,7 +3,10 @@ function list ({ query, params, uppy }, res, next) {
   const token = uppy.providerTokens[providerName]
 
   uppy.provider.list({ uppy, token, directory: params.id, query }, (err, data) => {
-    return err ? next(err) : res.json(data)
+    if (err) {
+      return err.isAuthError ? res.sendStatus(401) : next(err)
+    }
+    return res.json(data)
   })
 }
 

+ 7 - 2
packages/@uppy/companion/src/server/controllers/thumbnail.js

@@ -3,13 +3,18 @@
  * @param {object} req
  * @param {object} res
  */
-function thumbnail (req, res) {
+function thumbnail (req, res, next) {
   const providerName = req.params.providerName
   const id = req.params.id
   const token = req.uppy.providerTokens[providerName]
   const provider = req.uppy.provider
 
-  provider.thumbnail({ id, token }, (response) => response ? response.pipe(res) : res.sendStatus(404))
+  provider.thumbnail({ id, token }, (err, response) => {
+    if (err) {
+      err.isAuthError ? res.sendStatus(401) : next(err)
+    }
+    response ? response.pipe(res) : res.sendStatus(404)
+  })
 }
 
 module.exports = thumbnail

+ 20 - 3
packages/@uppy/companion/src/server/provider/drive/index.js

@@ -3,6 +3,7 @@ const request = require('request')
 const purest = require('purest')({ request })
 const logger = require('../../logger')
 const adapter = require('./adapter')
+const AuthError = require('../error')
 const DRIVE_FILE_FIELDS = 'kind,id,name,mimeType,ownedByMe,permissions(role,emailAddress),size,modifiedTime,iconLink,thumbnailLink,teamDriveId'
 const DRIVE_FILES_FIELDS = `kind,nextPageToken,incompleteSearch,files(${DRIVE_FILE_FIELDS})`
 const TEAM_DRIVE_FIELDS = 'teamDrives(kind,id,name,backgroundImageLink)'
@@ -33,7 +34,7 @@ class Drive {
       if (reqErr) {
         done(reqErr)
       } else if (listResponse.statusCode !== 200) {
-        done(new Error(`request to ${this.authProvider} returned ${listResponse.statusCode}`))
+        done(this._error(listResponse.statusCode))
       } else {
         done(null, this.adaptData(listResponse.body, teamDrives ? teamDrives.body : null, options.uppy))
       }
@@ -114,7 +115,12 @@ class Drive {
         logger.error(err, 'provider.drive.thumbnail.error')
         return done(null)
       }
-      done(body.thumbnailLink ? request(body.thumbnailLink) : null)
+
+      if (resp.statusCode !== 200) {
+        return done(this._error(resp.statusCode))
+      }
+
+      done(null, body.thumbnailLink ? request(body.thumbnailLink) : null)
     })
   }
 
@@ -124,7 +130,11 @@ class Drive {
         logger.error(err, 'provider.drive.size.error')
         return done(null)
       }
-      done(parseInt(body.size))
+
+      if (resp.statusCode !== 200) {
+        return done(this._error(resp.statusCode))
+      }
+      done(null, parseInt(body.size))
     })
   }
 
@@ -152,6 +162,13 @@ class Drive {
 
     return data
   }
+
+  _error (statusCode) {
+    if (statusCode === 401) {
+      return new AuthError()
+    }
+    return new Error(`request to ${this.authProvider} returned ${statusCode}`)
+  }
 }
 
 module.exports = Drive

+ 20 - 3
packages/@uppy/companion/src/server/provider/dropbox/index.js

@@ -2,6 +2,7 @@ const request = require('request')
 const purest = require('purest')({ request })
 const logger = require('../../logger')
 const adapter = require('./adapter')
+const AuthError = require('../error')
 
 class DropBox {
   constructor (options) {
@@ -38,7 +39,7 @@ class DropBox {
       if (reqErr) {
         done(reqErr)
       } else if (stats.statusCode !== 200) {
-        done(new Error(`request to ${this.authProvider} returned ${stats.statusCode}`))
+        done(this._error(stats.statusCode))
       } else {
         stats.body.user_email = userInfo.body.email
         done(null, this.adaptData(stats.body, options.uppy))
@@ -106,7 +107,12 @@ class DropBox {
       })
       .auth(token)
       .request()
-      .on('response', done)
+      .on('response', (resp) => {
+        if (resp.statusCode !== 200) {
+          return done(this._error(resp.statusCode))
+        }
+        done(null, resp)
+      })
       .on('error', (err) => {
         logger.error(err, 'provider.dropbox.thumbnail.error')
       })
@@ -127,7 +133,10 @@ class DropBox {
           return done(null)
         }
 
-        done(body.size)
+        if (resp.statusCode !== 200) {
+          return done(this._error(resp.statusCode))
+        }
+        done(null, parseInt(body.size))
       })
   }
 
@@ -151,6 +160,14 @@ class DropBox {
 
     return data
   }
+
+  _error (statusCode) {
+    if (statusCode === 401) {
+      return new AuthError()
+    }
+
+    return new Error(`request to ${this.authProvider} returned ${statusCode}`)
+  }
 }
 
 module.exports = DropBox

+ 13 - 0
packages/@uppy/companion/src/server/provider/error.js

@@ -0,0 +1,13 @@
+/**
+ * AuthError is error returned when an adapter encounters
+ * an authorization error while communication with its corresponding provider
+ */
+class AuthError extends Error {
+  constructor () {
+    super('invalid access token detected by Provider')
+    this.name = 'AuthError'
+    this.isAuthError = true
+  }
+}
+
+module.exports = AuthError

+ 21 - 3
packages/@uppy/companion/src/server/provider/instagram/index.js

@@ -3,6 +3,7 @@ const purest = require('purest')({ request })
 const utils = require('../../helpers/utils')
 const logger = require('../../logger')
 const adapter = require('./adapter')
+const AuthError = require('../error')
 
 class Instagram {
   constructor (options) {
@@ -24,7 +25,7 @@ class Instagram {
         if (err) {
           done(err)
         } else if (resp.statusCode !== 200) {
-          done(new Error(`request to ${this.authProvider} returned ${resp.statusCode}`))
+          done(this._error(resp))
         } else {
           done(null, this.adaptData(body))
         }
@@ -70,7 +71,12 @@ class Instagram {
         if (err) return logger.error(err, 'provider.instagram.thumbnail.error')
 
         request(body.data.images.thumbnail.url)
-          .on('response', done)
+          .on('response', (resp) => {
+            if (resp.statusCode !== 200) {
+              return done(this._error(resp))
+            }
+            done(null, resp)
+          })
           .on('error', (err) => {
             logger.error(err, 'provider.instagram.thumbnail.error')
           })
@@ -87,8 +93,12 @@ class Instagram {
           return done()
         }
 
+        if (resp.statusCode !== 200) {
+          return done(this._error(resp))
+        }
+
         utils.getURLMeta(this._getMediaUrl(body, query.carousel_id))
-          .then(({ size }) => done(size))
+          .then(({ size }) => done(null, size))
           .catch((err) => {
             logger.error(err, 'provider.instagram.size.error')
             done()
@@ -115,6 +125,14 @@ class Instagram {
     data.nextPagePath = adapter.getNextPagePath(items)
     return data
   }
+
+  _error (resp) {
+    if (resp.statusCode === 400 && resp.body && resp.body.meta.error_type === 'OAuthAccessTokenException') {
+      return new AuthError()
+    }
+
+    return new Error(`request to ${this.authProvider} returned ${resp.statusCode}`)
+  }
 }
 
 module.exports = Instagram