瀏覽代碼

@uppy/companion: catch "invalid initialization vector" instead of crashing (#4661)

prevent crashing companion

when async function rejects promise unhandled
Mikael Finstad 1 年之前
父節點
當前提交
a4b86839ad

+ 1 - 0
packages/@uppy/companion/src/server/helpers/utils.js

@@ -126,6 +126,7 @@ module.exports.decrypt = (encrypted, secret) => {
     throw new Error('Invalid encrypted value. Maybe it was generated with an old Companion version?')
   }
 
+  // NOTE: The first 32 characters are the iv, in hex format. The rest is the encrypted string, in base64 format.
   const iv = Buffer.from(encrypted.slice(0, 32), 'hex')
   const encryptionWithoutIv = encrypted.slice(32)
 

+ 33 - 31
packages/@uppy/companion/src/server/provider/credentials.js

@@ -70,42 +70,44 @@ async function fetchProviderKeys (providerName, companionOptions, credentialRequ
  */
 exports.getCredentialsOverrideMiddleware = (providers, companionOptions) => {
   return async (req, res, next) => {
-    const { authProvider, override } = req.params
-    const [providerName] = Object.keys(providers).filter((name) => providers[name].authProvider === authProvider)
-    if (!providerName) {
-      next()
-      return
-    }
+    try {
+      const { authProvider, override } = req.params
+      const [providerName] = Object.keys(providers).filter((name) => providers[name].authProvider === authProvider)
+      if (!providerName) {
+        next()
+        return
+      }
 
-    if (!companionOptions.providerOptions[providerName]?.credentialsURL) {
-      next()
-      return
-    }
+      if (!companionOptions.providerOptions[providerName]?.credentialsURL) {
+        next()
+        return
+      }
 
-    const dynamic = oAuthState.getDynamicStateFromRequest(req)
-    // only use state via session object if user isn't making intial "connect" request.
-    // override param indicates subsequent requests from the oauth flow
-    const state = override ? dynamic : req.query.state
-    if (!state) {
-      next()
-      return
-    }
+      const dynamicState = oAuthState.getDynamicStateFromRequest(req)
+      // only use state via session object if user isn't making intial "connect" request.
+      // override param indicates subsequent requests from the oauth flow
+      const state = override ? dynamicState : req.query.state
+      if (!state) {
+        next()
+        return
+      }
 
-    const preAuthToken = oAuthState.getFromState(state, 'preAuthToken', companionOptions.secret)
-    if (!preAuthToken) {
-      next()
-      return
-    }
+      // pre auth token is companionKeysParams encoded and encrypted by companion before the oauth flow,
+      // I believe this has been done so that it cannot be modified by the client later.
+      const preAuthToken = oAuthState.getFromState(state, 'preAuthToken', companionOptions.secret)
+      if (!preAuthToken) {
+        next()
+        return
+      }
 
-    let payload
-    try {
-      payload = tokenService.verifyEncryptedToken(preAuthToken, companionOptions.preAuthSecret)
-    } catch (err) {
-      next()
-      return
-    }
+      let payload
+      try {
+        payload = tokenService.verifyEncryptedToken(preAuthToken, companionOptions.preAuthSecret)
+      } catch (err) {
+        next()
+        return
+      }
 
-    try {
       const credentials = await fetchProviderKeys(providerName, companionOptions, payload)
 
       res.locals.grant = {