Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@uppy/companion: remove oauthOrigin #5311

Open
wants to merge 4 commits into
base: 4.x
Choose a base branch
from
Open

@uppy/companion: remove oauthOrigin #5311

wants to merge 4 commits into from

Conversation

aduh95
Copy link
Member

@aduh95 aduh95 commented Jul 3, 2024

No description provided.

@aduh95 aduh95 requested a review from Murderlon July 3, 2024 17:54
Copy link
Contributor

github-actions bot commented Jul 3, 2024

Diff output files
diff --git a/packages/@uppy/companion/lib/config/companion.js b/packages/@uppy/companion/lib/config/companion.js
index 5931656..1839910 100644
--- a/packages/@uppy/companion/lib/config/companion.js
+++ b/packages/@uppy/companion/lib/config/companion.js
@@ -107,8 +107,8 @@ const validateConfig = (companionOptions) => {
       "startup.uploadUrls",
     );
   }
-  if (!companionOptions.oauthOrigin) {
-    throw new TypeError("Option oauthOrigin is required. To disable security, pass \"*\"");
+  if (companionOptions.corsOrigins == null) {
+    throw new TypeError("Option corsOrigins is required. To disable security, pass true");
   }
   if (
     periodicPingUrls != null && (!Array.isArray(periodicPingUrls)
diff --git a/packages/@uppy/companion/lib/server/controllers/connect.d.ts b/packages/@uppy/companion/lib/server/controllers/connect.d.ts
index e2b73d9..668b7e4 100644
--- a/packages/@uppy/companion/lib/server/controllers/connect.d.ts
+++ b/packages/@uppy/companion/lib/server/controllers/connect.d.ts
@@ -1,2 +1,2 @@
-declare function _exports(req: object, res: object): void;
+declare function _exports(req: object, res: object, next: any): void;
 export = _exports;
diff --git a/packages/@uppy/companion/lib/server/controllers/connect.js b/packages/@uppy/companion/lib/server/controllers/connect.js
index 374cd76..a0f3776 100644
--- a/packages/@uppy/companion/lib/server/controllers/connect.js
+++ b/packages/@uppy/companion/lib/server/controllers/connect.js
@@ -1,42 +1,21 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
 const oAuthState = require("../helpers/oauth-state");
+function isOriginAllowed(origin, allowedOrigins) {
+  if (Array.isArray(allowedOrigins)) {
+    return allowedOrigins.some(allowedOrigin => isOriginAllowed(origin, allowedOrigin));
+  }
+  if (typeof allowedOrigins === "string") {
+    return origin === allowedOrigins;
+  }
+  return allowedOrigins.test?.(origin) ?? !!allowedOrigins;
+}
 const queryString = (params, prefix = "?") => {
   const str = new URLSearchParams(params).toString();
   return str ? `${prefix}${str}` : "";
 };
-/**
- * initializes the oAuth flow for a provider.
- *
- * @param {object} req
- * @param {object} res
- */
-module.exports = function connect(req, res) {
-  const { secret, oauthOrigin } = req.companion.options;
-  const stateObj = oAuthState.generateState();
-  // not sure if we need to store origin in the session state (e.g. we could've just gotten it directly inside send-token)
-  // but we're afraid to change the logic there
-  if (!Array.isArray(oauthOrigin)) {
-    // If the server only allows a single origin, we ignore the client-supplied
-    // origin from query because we don't need it.
-    stateObj.origin = oauthOrigin;
-  } else if (oauthOrigin.length < 2) {
-    // eslint-disable-next-line prefer-destructuring
-    stateObj.origin = oauthOrigin[0];
-  } else {
-    // If we have multiple allowed origins, we need to check the client-supplied origin from query.
-    // If the client provides an untrusted origin,
-    // we want to send `undefined`. `undefined` means `/`, which is the same origin when passed to `postMessage`.
-    // https://html.spec.whatwg.org/multipage/web-messaging.html#dom-window-postmessage-options-dev
-    const { origin } = JSON.parse(atob(req.query.state));
-    stateObj.origin = oauthOrigin.find(o => o === origin);
-  }
-  if (req.companion.options.server.oauthDomain) {
-    stateObj.companionInstance = req.companion.buildURL("", true);
-  }
-  if (req.query.uppyPreAuthToken) {
-    stateObj.preAuthToken = req.query.uppyPreAuthToken;
-  }
+function encodeStateAndRedirect(req, res, stateObj) {
+  const { secret } = req.companion.options;
   const state = oAuthState.encodeState(stateObj, secret);
   const { providerClass, providerGrantConfig } = req.companion;
   // pass along grant's dynamic config (if specified for the provider in its grant config `dynamic` section)
@@ -62,4 +41,38 @@ module.exports = function connect(req, res) {
   });
   // Now we redirect to grant's /connect endpoint, see `app.use(Grant(grantConfig))`
   res.redirect(req.companion.buildURL(`/connect/${oauthProvider}${qs}`, true));
+}
+/**
+ * initializes the oAuth flow for a provider.
+ *
+ * @param {object} req
+ * @param {object} res
+ */
+module.exports = function connect(req, res, next) {
+  const stateObj = oAuthState.generateState();
+  if (req.companion.options.server.oauthDomain) {
+    stateObj.companionInstance = req.companion.buildURL("", true);
+  }
+  if (req.query.uppyPreAuthToken) {
+    stateObj.preAuthToken = req.query.uppyPreAuthToken;
+  }
+  stateObj.origin = res.getHeader("Access-Control-Allow-Origin");
+  if (!stateObj.origin) {
+    const { corsOrigins } = req.companion.options;
+    const { origin } = JSON.parse(atob(req.query.state));
+    if (typeof corsOrigins === "function") {
+      corsOrigins(origin, (err, finalOrigin) => {
+        if (err) {
+          next(err);
+        }
+        stateObj.origin = finalOrigin;
+        encodeStateAndRedirect(req, res, stateObj);
+      });
+      return;
+    }
+    if (isOriginAllowed(origin, req.companion.options.corsOrigins)) {
+      stateObj.origin = origin;
+    }
+  }
+  encodeStateAndRedirect(req, res, stateObj);
 };
diff --git a/packages/@uppy/companion/lib/server/controllers/index.d.ts b/packages/@uppy/companion/lib/server/controllers/index.d.ts
index a782333..044ac31 100644
--- a/packages/@uppy/companion/lib/server/controllers/index.d.ts
+++ b/packages/@uppy/companion/lib/server/controllers/index.d.ts
@@ -6,7 +6,7 @@ export let thumbnail: typeof import("./thumbnail");
 export let list: typeof import("./list");
 export let simpleAuth: typeof import("./simple-auth");
 export let logout: typeof import("./logout");
-export let connect: (req: any, res: any) => void;
+export let connect: (req: any, res: any, next: any) => void;
 export let preauth: typeof import("./preauth");
 export let redirect: (req: any, res: any) => void;
 export let refreshToken: typeof import("./refresh-token");
diff --git a/packages/@uppy/companion/lib/standalone/helper.js b/packages/@uppy/companion/lib/standalone/helper.js
index fa5d55f..5c3e44d 100644
--- a/packages/@uppy/companion/lib/standalone/helper.js
+++ b/packages/@uppy/companion/lib/standalone/helper.js
@@ -40,9 +40,18 @@ const hasProtocol = (url) => {
 const companionProtocol = process.env.COMPANION_PROTOCOL || "http";
 function getCorsOrigins() {
   if (process.env.COMPANION_CLIENT_ORIGINS) {
-    return process.env.COMPANION_CLIENT_ORIGINS
-      .split(",")
-      .map((url) => (hasProtocol(url) ? url : `${companionProtocol}://${url}`));
+    switch (process.env.COMPANION_CLIENT_ORIGINS) {
+      case "true":
+        return true;
+      case "false":
+        return false;
+      case "*":
+        return "*";
+      default:
+        return process.env.COMPANION_CLIENT_ORIGINS
+          .split(",")
+          .map((url) => (hasProtocol(url) ? url : `${companionProtocol}://${url}`));
+    }
   }
   if (process.env.COMPANION_CLIENT_ORIGINS_REGEX) {
     return new RegExp(process.env.COMPANION_CLIENT_ORIGINS_REGEX);
@@ -179,9 +188,6 @@ const getConfigFromEnv = () => {
     corsOrigins: getCorsOrigins(),
     testDynamicOauthCredentials: process.env.COMPANION_TEST_DYNAMIC_OAUTH_CREDENTIALS === "true",
     testDynamicOauthCredentialsSecret: process.env.COMPANION_TEST_DYNAMIC_OAUTH_CREDENTIALS_SECRET,
-    oauthOrigin: process.env.COMPANION_OAUTH_ORIGIN?.includes(",")
-      ? process.env.COMPANION_OAUTH_ORIGIN.split(",")
-      : process.env.COMPANION_OAUTH_ORIGIN,
   };
 };
 /**


Allowed CORS Origins (default `true`). Passed as the `origin` option in
[cors](https://github.com/expressjs/cors#configuration-options))
Allowed CORS Origins. Passed as the `origin` option in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we explain what should be passed? Entire URI as string? Compatible with everything cors supports?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a link to the docs (also it's a bit unrelated to this PR)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what makes it confusing, I read that link I and I pass a regex. Then it crashes because postMessage does not support a regex. So it is related to this PR to clarify what is now support and remove that link

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No no, a regex would work just fine

@@ -6,8 +6,10 @@ These cover all the major Uppy versions and how to migrate to them.

- End-of-Life versions of Node.js are no longer supported (use latest 18.x LTS,
20.x LTS, or 22.x current).
- Setting the `oauthOrigin` option is now required. To get back to the unsafe
behavior of the previous version, set it to `'*'`.
- Setting the `corsOrigin` option is now required. You should define the list of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's link to this option in the docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants