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

Adding a check for existence of the window object. #158

Closed
wants to merge 1 commit into from
Closed

Adding a check for existence of the window object. #158

wants to merge 1 commit into from

Conversation

1Copenut
Copy link

@1Copenut 1Copenut commented Nov 27, 2022

UPDATE 27 November, 7:46 pm GMT-6
The proposed change I've PR'ed does suppress the window object error in Cloudflare Workers, but when the actual sanitize() method is called, a new error emerges:

TypeError: import_isomorphic_dompurify.default.sanitize is not a function

I'm not great with TypeScript, so I'm having some trouble getting to the root cause of this issue. I'll leave the PR open in case it still offers an improvement, and will see if I can find a better refactor. This library is still my first choice for preventing XSS when constructing emails or inserting user data.


Hello. I found isomorphic-dompurify while looking for a good library to remove XSS vectors while building a Cloudflare Worker to collect form information and send myself an email. When I tried to publish my Worker, I received a "window not defined" error, and traced it to the browser.js file.

Using the Flavio Copes article referenceerror: window is not defined, how to solve for inspiration, I wrapped your module.exports with a type check for the window object.

This passes the tests in your repo, passes my Jest unit tests for removing bad markup, and publishes my Cloudflare worker with no errors.

Let me know if this is too simplistic a solution or it needs further unit tests.

@1Copenut 1Copenut marked this pull request as draft November 28, 2022 01:46
@kkomelin
Copy link
Owner

kkomelin commented Nov 28, 2022

@1Copenut Thanks for your PR. Could you please share the code which you're using to include the isomorphic-dompurity library into your code?

@1Copenut
Copy link
Author

@kkomelin Sure thing. The JS sample below shows the entire use case. I'm exporting the file into an API call in the main Worker file.

import DOMPurify from "isomorphic-dompurify";

const textTemplate = (data) => {
  const { firstName, lastName, email, message, optedIn } = data;
  const telephone = data.telephone ? data.telephone : "Not provided";

  const cleanFirstName = DOMPurify.sanitize(firstName);
  const cleanLastName = DOMPurify.sanitize(lastName);
  const cleanEmail = DOMPurify.sanitize(email);
  const cleanTelephone = DOMPurify.sanitize(telephone);
  const cleanMessage = DOMPurify.sanitize(message);
  const cleanOptedIn = DOMPurify.sanitize(optedIn);

  return `
    Simple Contact Form
    ----------------------------------------
    Name:       ${cleanFirstName} ${cleanLastName}
    Email:      ${cleanEmail}
    Telephone:  ${cleanTelephone}
    Message:    ${cleanMessage}
    Opted in:   ${cleanOptedIn}`;
};

export default textTemplate;

@kkomelin
Copy link
Owner

kkomelin commented Nov 28, 2022

Thanks for the code sample @1Copenut

I'm not familiar with Cloudflare Workers but it looks strange for me that it uses browser.js file instead of the main index.js which is aimed to be run on a server. And that's probably why the script doesn't find the window object because the window object used in the browser.js is only available in the browser. The index.js file uses a fallback for the window object which is provided by the JSDom library.

Your code cannot solve the problem, unfortunately. Instead, you need to somehow force the Worker to use the index.js file. I'm thinking about something like this:

import DOMPurify from "isomorphic-dompurify/index";

Can you please test it for me? I don't have a configured environment at the moment to test it myself.

@1Copenut
Copy link
Author

1Copenut commented Nov 28, 2022

Yes, I can do that late tonight and will report back in the next day or two on progress or errors. Much appreciated.

Edit: Looking at Cloudflare's Worker docs, they (workers) run directly on the V8 engine. Cloudflare docs: How Workers works

@kkomelin
Copy link
Owner

Thanks for the link @1Copenut Will take a look at it.
If it's v8, there shouldn't be any issues.
Will also try to signup and test tomorrow.

@1Copenut
Copy link
Author

When I try to import isomorphic-dompurify using the suggested path, I get a number of errors (38) that stem from this declaration:

✘ [ERROR] [plugin checkForNodeBuiltins] Detected a Node builtin module import while Node compatibility is disabled.
Add node_compat = true to your wrangler.toml file to enable Node compatibility.

The errors are some repetition of that original message.

@kkomelin
Copy link
Owner

kkomelin commented Nov 29, 2022

And what does happen if you follow the instructions from the error message?

Add node_compat = true to your wrangler.toml file to enable Node compatibility.

@1Copenut
Copy link
Author

Adding node_compat = true to the wrangler.toml file yields a new error:

✘ [ERROR] Could not resolve "perf_hooks"

  node_modules/jsdom/lib/jsdom/utils.js:5:26:
  5 │ const perfHooks = require("perf_hooks");~~~~~~~~~~~~

  The package "perf_hooks" wasn't found on the file system but is built into node. Are you trying to
  bundle for node? You can use "platform: 'node'" to do that, which will remove this error.

✘ [ERROR] Build failed with 1 error:
  node_modules/jsdom/lib/jsdom/utils.js:5:26: ERROR: Could not resolve "perf_hooks"

I also tried changing the import statement back to import DOMPurify from "isomorphic-dompurify"; for thoroughness. This yielded the original window object error.

@kkomelin
Copy link
Owner

Thanks @1Copenut,

What if we try to import JSDOM dependency additionally:

import jsdom from "jsdom";

or

const jsdom = require("jsdom");

@1Copenut
Copy link
Author

1Copenut commented Nov 29, 2022

I'll give that a shot this evening and follow up with results. Thank you @kkomelin for taking time to look into this issue.

@1Copenut
Copy link
Author

1Copenut commented Dec 2, 2022

@kkomelin

I'm still seeing the previous error after adding JSDOM as its own import, and another one I forgot to include in my last message:

✘ [ERROR] Could not resolve "isomorphic-dompurify"

    src/email-text-template.js:1:22:
      1 │ import DOMPurify from "isomorphic-dompurify";~~~~~~~~~~~~~~~~~~~~~~

  You can mark the path "isomorphic-dompurify" as external to exclude it from the bundle, which will
  remove this error.

✘ [ERROR] Could not resolve "perf_hooks"

    node_modules/jsdom/lib/jsdom/utils.js:5:26:
      5 │ const perfHooks = require("perf_hooks");~~~~~~~~~~~~

  The package "perf_hooks" wasn't found on the file system but is built into node. Are you trying to
  bundle for node? You can use "platform: 'node'" to do that, which will remove this error.

I did a bit more Googling this evening and came up with two more Cloudflare resources that shed light on packages that work with Workers. The tl;dr seems to favor packages that are bundled with Webpack and don't rely on Node native packages or the window object.

At this point it feels like I've exhausted most of my good options. I fully support closing this PR and finding another solution to sanitize inputs for the time being.

@kkomelin
Copy link
Owner

kkomelin commented Dec 2, 2022

Hi @1Copenut,

Thank you for your research and collaboration. Sorry I couldn't help. We have already had issues with serverless environments before (e.g. #54), so I think we're not that suitable for such specific environments, at least yet.

As for this PR, yes, since your code doesn't solve the problem, we could close the PR. If you still want to proceed with making isomorphic-dompurify work in Workers, please create a separate issue.

Thanks again. I wish you find a working solution for your problem.

@kkomelin kkomelin closed this Dec 2, 2022
@1Copenut 1Copenut deleted the feature/window-object-cloudflare branch December 2, 2022 14:13
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.

2 participants