Giter VIP home page Giter VIP logo

isomorphic-dompurify's Introduction

Isomorphic DOMPurify

npm version Test Status Bundlephobia Minified Size

The library makes it possible to seamlessly use DOMPurify on server and client in the same way. It does nothing by itself except providing an isomorphic/universal wrapper around DOMPurify, so all credits go to DOMPurify authors and contributors.

DOMPurify - a DOM-only, super-fast, uber-tolerant XSS sanitizer for HTML, MathML and SVG. DOMPurify works with a secure default, but offers a lot of configurability and hooks.

Motivation

DOMPurify needs a DOM tree to base on, which is not available in Node by default. To work on the server side, we need a fake DOM to be created and supplied to DOMPurify. It means that DOMPurify initialization logic on the server is not the same as on the client.

This project was born with the idea of encapsulating DOMPurify initialization details and providing an easy way to import the library on both, server and client, for example in Next.js apps.

It was inspired by Isomorphic Unfetch.

Requirements

isomorphic-dompurify Node.js Environment
<=0.19.0 >=12 Server
>=0.20.0 >=14 Server
>=1.4.0 >=16 Server
>=1.10.0 >=18 Server

Installation

$ npm i isomorphic-dompurify

Updates

Please note that DOMPurify library doesn't follow Semantic Versioning, so we have to release every change as a minor version because we cannot be 100% sure whether new features are added to patch DOMPurify releases or not.

Usage

Import:

import DOMPurify from "isomorphic-dompurify";

Importing the entire module for the client/browser version is recommended.

Sanitize:

const clean = DOMPurify.sanitize(dirtyString);

or with config:

const clean = DOMPurify.sanitize(dirtyString, { USE_PROFILES: { html: true } });

Known Issues

  1. Next.js and Remix are mistakenly trying to use the browser entry point on server, which causes the Window is not defined issue. #228 #214 vercel/next.js#58142
  2. Can't resolve 'canvas' on Next.js serverless app
  3. Starting from 0.16.0, there is a dependency conflict which causes ReferenceError: TextEncoder is not defined

License

DOMPurify - Apache 2.0 or MPL 2.0 © 2015 Mario Heiderich

Isomorphic DOMPurify - MIT License © 2020 Konstantin Komelin and contributors

isomorphic-dompurify's People

Contributors

bohdanyavorskyi avatar dependabot-preview[bot] avatar dependabot[bot] avatar himanshubari21 avatar karlhorky avatar kkomelin avatar nicholasellul avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

isomorphic-dompurify's Issues

Requirements for Node.js 14

Hi! I got an error when I exec next build

image

This is what I got when I install 1.8.0 version

image

According to this,

image

I downgrade to 1.3.0, and it worked!
so I thought the document should update for Node.js 14

image

Dependencies:

  • node v14.21.3
  • react 18.2.0
  • next 12.3.4
  • isomorphic-dompurify 1.8.0

target blank get added to every url

Hi,
I am using this library in nextjs SSR environment.
No custom rule applied or anything. I am usingafterSanitizeAttributes hook to add target attribute. however target=_blank get added to every available link with/without target attribute.

    // set all elements owning target to target=_blank
    if ("target" in node) {
      node.setAttribute("target", "_blank");
      node.setAttribute("rel", "noopener");
    }
  });
  const clean = DOMPurify.sanitize(content); 

Do i need to configure anything else to selectively add target? thanks

Can't resolve 'canvas' on next.js serverless app

What's the problem

I built a next.js application with serveless option, but simply importing this library it throws this error:

Failed to compile.
ModuleNotFoundError: Module not found: Error: Can't resolve 'canvas' in '/.../node_modules/jsdom/lib/jsdom'
> Build error occurred

I already tried to add canvas library but this doesn't fix the problem and it throws another error.

Step to reproduce

Add to next.config.js:

module.exports = {
  target: 'serverless'
}

Run next build

Basic Info:

  • "isomorphic-dompurify": "^0.12.0",
  • "next": "^10.0.8",
  • "react": "^17.0.1",
  • "react-dom": "^17.0.1"

This issue could be related to #35 , but i don't use umijs.

Question: How Isomorphic Works

Let me start by saying: thank you so much for this library! I just used it and it works like a charm with my NextJS implementation. I just don't understand why (and that hurts 😄 ), so, I admit this is mostly just my lack of understanding around how this is working, but if you'll entertain me...

Am I right in the following understanding of how this library works:

  1. function r(m){return m && m.default || m;} returns the default export if available, else just whatever m is (i.e. a module)
  2. We export global.DOMPurify if it exists (meaning global exists, meaning we're in node)... or
  3. typeof process === undefined meaning we're not in node (is this not redundant?) and so we can return just dompurify since we don't need jsdom on the client-side, else
  4. we are in node, so we need to use JSDOM to initialize a virtual(?) DOM with JS for DOMPurify server-side?
function r(m){return m && m.default || m;}
module.exports = global.DOMPurify = global.DOMPurify || (
	typeof process === 'undefined' ? r(require('dompurify')) : (function() {
    const DOMPurifyInitializer = r(require('dompurify'));
    const { JSDOM } = r(require('jsdom'));
    const { window } = new JSDOM('<!DOCTYPE html>');
    return DOMPurifyInitializer(window);
	})()
);

For reference, here's me confirming that process would be defined in node

$ node
Welcome to Node.js v12.16.2.
Type ".help" for more information.
> typeof process
'object'

Sanitize returns empty string when `PARSER_MEDIA_TYPE: application/xhtml+xml` and void tags

Bug

DOMPurify.sanitize returns an empty string when ran on HTML files containing void elements when application/xhtml+xml is set as parser media type.

Version: 2.6.0

Input

<html lang="en">
<head>
    <title>Sample HTML5 Page</title>
</head>
<body>
    <p>Hello</p>
    <br>
</body>
</html>

Given output

Empty string

Expected output

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
    <title>Sample HTML5 Page</title>
</head>
<body>
    <p>Hello</p>
    <br />
</body>
</html>

Same outcome for other void elements, such as meta or link tags

ESM Support

Hi! I'm trying to use this package as a transitive dependency in Deno via esm.sh. Unfortunately sanitize is not a proper named export. I can't change the way this package is imported (e.g. import * as dompurify from "...") because it's a transitive dependency. What do you think about providing support for ESM natively?

I see that isomorphic-unfetch uses Node's conditional exports and provides separate browser, .cjs and .mjs implementations. Maybe this could be done from a single source file and a tool like rollup to cross-build .cjs and .mjs formats.

Check package size for a browser

A friend of mine asked about package size and requested displaying it somewhere in README.

I checked the size and noticed that JSDom dependency is huge (2.9MiB).

We need to check whether JSDom is always loaded at the front-end and if it's the case find a way to avoid that.

_isomorphicDompurify.default.sanitize is not a function error in jest environment

Whats the problem.

I am using ismorphic-dompurify in my application which uses RTL and jest for tests setup. When I am trying to run the component's tests which uses DOMPurify.sanitize from the library the tests environment throws an error as shown in screen shot below.

Screenshot 2022-08-29 at 9 27 58 PM

Can you guys help me with this ?

Our package versions for notable libraries are as follows

"isomorphic-dompurify" - 0.19.0 (because we need to support some applications which use node version equal to 12
"jest" - 26.1.0,
"@testing-library/jest-dom": "^5.11.1",
"@testing-library/react": "^10.4.7",
"@testing-library/react-hooks": "^3.4.1",

Isomorphic Dompurify Remix support ?

Hi! I'm trying to use isomorphic-dompurify to sanitize html in a remix application (more specifically hydrogen), but I keep having this error
Untitled-1

I could use the dompurify and sanitize on the client side, but would prefer if it would on the server too.

Has anyone looked into this?

Request body is being removed

I'm using version 0.20.0 and node.js version: v14.19.1 and restify version:8.5.1
When I'm using sanitized() method and passing request object inside it, only request headers are being kept everything else is being removed including request body of POST request. Is there any way to keep the request body? Or is it a bug?

Bumping to 0.16.0 - ReferenceError: TextEncoder is not defined

When installing - "isomorphic-dompurify": "^0.16.0" I get the following error within a jest test that previously passed.

Error: ReferenceError: TextEncoder is not defined

js file:

import DOMPurify from "isomorphic-dompurify";

return DOMPurify.sanitize(input.trim(), { ADD_ATTR: ["target"] });

Test:

import sanitize from "./sanitizeHtml";

describe("sanitize", () => {
    it("remove js from input", () => {
        expect(sanitize("<img onload='alert(1)' />")).toEqual("<img>");
    });
});

Any ideas what this may be? Thanks in advance

Request for SemVer Adherence in Future Releases

Hi

I hope this message finds you well. I wanted to bring to your attention an issue that we encountered with the recent release, 1.10.0. It seems to have introduced a dependency on a higher version of Node.js, which has caused disruptions in our pipeline.

Upon reviewing the changes made in the release, it appears that a major version increment (2.0.0) might have been more appropriate, given the backward-incompatible change introduced with the new Node.js version requirement.

As a user of your project, I understand that maintaining version compatibility can be challenging, and I appreciate the effort you put into improving the software. However, adhering to Semantic Versioning (SemVer) guidelines is crucial for users to anticipate and manage potential breaking changes.

I kindly request that, moving forward, you consider following SemVer principles more closely, especially when making changes that impact compatibility. This will greatly assist users in planning for and migrating to new versions without unexpected disruptions.

If there are specific reasons for choosing a different versioning approach in this instance, I'd appreciate any insights you can provide to help us better understand the decision.

Thank you for your attention to this matter, and I look forward to your insights on the issue.

Best regards

Cannot find package on server with Nuxt

We are using nuxt 3 (ssr true) application. Trying to use this package, its working fine in local. But when we try to deploy it, it fails with this issue.

[nuxt] [request error] [unhandled] [500] Cannot find package 'isomorphic-dompurify' imported from /home/site/wwwroot/server/chunks/app/server.mjs

We are using import statement as follows

import DOMPurify from "isomorphic-dompurify";

Let me know if I need to also add some other dependency. I already added jsdom and Dompurify separately and tried deploying.

Web Worker Support

Web Workers resolve to the browser.js however window is not defined thus causing an undefined reference.
Using globalThis or self instead of window could allow this file to work in web workers too.

Uncaught ReferenceError: window is not defined
    at node_modules/.pnpm/[email protected][email protected]/node_modules/isomorphic-dompurify/browser.js (isomorphic-dompurify.js?v=650fd638:949:22)

Build error when using isomorphic-dompurify in angular 15 universal

I'm trying to use isomorphic dompurify's sanitize function, in my angular application, which uses angular universal for server side rendering. While there is no error when running the application as a client side rendered one. server side rendering is not working.

Screenshot 2023-07-01 at 2 53 51 PM

I'm importing the sanitize function using ES6 syntax:

import { sanitize } from 'isomorphic-dompurify';

Is this a known issue.

I'm currently using

"angular" : 15.2.2
"typescript": "4.9.4"
"node" : 16.19.1
"isomorphic-dompurify": "^1.7.0"

usage import issue with vite named export 'sanitize' not found

I followed the usage example for import in a basic Astro project. Typescript is good with it and Astro seems good with it in dev mode until the page loads or refreshes. Then I get a 500 server error in devtools.

On the server side in the console I get

23:43:58 [ERROR] [vite] Named export 'sanitize' not found. The requested module 'isomorphic-dompurify' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'isomorphic-dompurify';
const {sanitize} = pkg;

As the hint in the terminal shows, if I do the following, it works

import DOMPurify from 'isomorphic-dompurify';

// either this way
const { sanitize } = DOMPurify;
const clean = sanitize(dirtyHTML);

// or this way
const clean = DOMPurify.sanitize(dirtyHTML);

I didn't know if this is an issue with exports in the package or vite or just need a note under the usage section. But wanted to let you know.

String is being sanitized

Using:
isomorphic-dompurify: 1.9.0
next: 14.0.1
node: 18.17.1
quill: 1.3.7

I'm trying to sanitize a string coming from Quill Editor.
I'm using the example code from the website https://cure53.de/purify to testing the sanitize

// the API
import DOMPurify from 'isomorphic-dompurify'

export async function POST(request: NextRequest) {
  const body = await request.json()

  // zod validation
  const validation = createIssueSchema.safeParse(body)
  if (!validation.success)
    return NextResponse.json(validation.error.format(), { status: 400 })

  // sanitize HTML
  const cleanTitle = DOMPurify.sanitize(body.title)
  const cleanDescription = DOMPurify.sanitize(body.description)

  const newIssue = await prisma.issue.create({
    data: {
      title: cleanTitle,
      description: cleanDescription
    }
  })

  return NextResponse.json(newIssue, { status: 201 })
}

The body.description comes in the format

"<p>123&lt;a href=' javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#xA0javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x1680;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x180E;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2000;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2001;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2002;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2003;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2004;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2005;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2006;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2006;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2007;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2008;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x2009;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x200A;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x200B;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x205f;javascript:alert(1)'&gt;CLICK&lt;/a&gt;&lt;a href='&amp;#x3000;javascript:alert(1)'&gt;CLICK&lt;/a&gt;</p>"

In the body.title I'm using default HTML input, comes in the format

"123<a href=' javascript:alert(1)'>CLICK</a><a href='&#xA0javascript:alert(1)'>CLICK</a><a href='&#x1680;javascript:alert(1)'>CLICK</a><a href='&#x180E;javascript:alert(1)'>CLICK</a><a href='&#x2000;javascript:alert(1)'>CLICK</a><a href='&#x2001;javascript:alert(1)'>CLICK</a><a href='&#x2002;javascript:alert(1)'>CLICK</a><a href='&#x2003;javascript:alert(1)'>CLICK</a><a href='&#x2004;javascript:alert(1)'>CLICK</a><a href='&#x2005;javascript:alert(1)'>CLICK</a><a href='&#x2006;javascript:alert(1)'>CLICK</a><a href='&#x2006;javascript:alert(1)'>CLICK</a><a href='&#x2007;javascript:alert(1)'>CLICK</a><a href='&#x2008;javascript:alert(1)'>CLICK</a><a href='&#x2009;javascript:alert(1)'>CLICK</a><a href='&#x200A;javascript:alert(1)'>CLICK</a><a href='&#x200B;javascript:alert(1)'>CLICK</a><a href='&#x205f;javascript:alert(1)'>CLICK</a><a href='&#x3000;javascript:alert(1)'>CLICK</a>"

In the body.title the sanitize works, in the body.description don't works!
The only difference I found that body.description string starts with the <p> tag, because it comes from the editor.

Would that be the problem?

Next.js build error: Window is not defined

isomorphic-dompurify version - 1.9.0
Node version - 18.18.0
Next.js version - 13.5.4
React version - 18.2.0

I am importing my company's React component library that makes use of Isomorphic DOMPurify.
No issues when using it in a client-side app.
However, when running yarn build in my Next.js project I am getting ReferenceError: window is not defined and the path in the logs points to the following line of code: var ti=window.DOMPurify||(window.DOMPurify=Vl().default||Vl());

Am I doing something incorrectly?

Here's a repo for the Next.js app - https://github.com/mikeriley131/next-idp-test
And here's a repo for the component library - https://github.com/mikeriley131/pyrographic-react-component-library

The component library is "npm link"ed to the next app.

When I add the Button component from the library to the Next.js app, it throws the following error:

Server Error
Error: window is not defined

This error happened while generating the page. Any console logs will be displayed in the terminal window.
Source
../pyrographic-react-component-library/dist/components/Button/index.js (509:9) @ window

  507 | }(Ce)), Ce.exports;
  508 | }
> 509 | var fn = window.DOMPurify || (window.DOMPurify = ht().default || ht());
      |       ^
  510 | function pn(re) {
  511 | const { className: xe, ...z } = re;
  512 | return /* @__PURE__ */ rn("button", { className: `${xe} ${ln.button}`, ...z, children:

dompurify.sanitize clears everything except for whats inside of <body>

image
the code:

	if (userfound) {
		var toSend;
		toSend = fs.readFileSync("./pages/profile.html", "utf-8")
		.replaceAll("${username}", userdata["username"])
		.replaceAll("${bio}", userdata["bio"])
		.replaceAll("${pfpurl}", userdata["profile-picture-url"])

		res.send(dompurify.sanitize(toSend));
	}

the webpage html:

<html>
	<head>
		<title>Antisocial</title>
		<style>
			body {
				margin:0px;
				text-align: left;
				font-family:'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
			}
			.leftbar {
				position:absolute;
				top: 0px;
				left: 0px;
				background-color: #007e45;
				width: 250px;
				height: 100vh;
				font-weight: bold;
				font-size: 115%;
				margin: 0px auto;
				padding-left: 10px;
			}
			/*.leftbar a {
				color: white;
				text-decoration: none;
			}*/
			.leftbar button {
				background-color: #005500;
				color: white;
				border-radius: 12%;
				font-size: 25px;
				border: none;
				transition-duration: 250ms;
				cursor: pointer;
				margin-bottom: 5px;
			}
			.leftbar button:hover {
				background-color: #009900;
			}
			.leftbar_settings {
				bottom: 10px;
			}
			.mainbody {
				position: absolute;
				top: 5px;
				left: 275px;
				font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
				color: black;
				width: 100% - 275px;
			}
			button {
				background-color: #008800;
				font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
				color: white;
				border: none;
				font-size: large;
				cursor: pointer;
			}
			button:hover {
				background-color: #00bb00;
			}
			img {
				border-style: solid;
			}
		</style>
		<meta name="og:title" content="$USERNAME$'s profile on Antisocial"/>
		<meta name="og:description" content="$USERBIO$"/>
		<meta name="og:color" content="#00aa00"/>
		<meta name="og:image" content="$PFPURL$"/>
	</head>
	<body>
		<div class="leftbar">
			<h1>Antisocial</h1>
			<a href="/"><button>Home</button><br></a>
			<a href="/explore"><button>Explore</button><br></a>
			<a href="/profile"><button>Profile</button><br></a>
			<a href="/settings"><button class="leftbar_settings">Settings</button><br></a>
		</div>
		<div class="mainbody">
			<img src="${pfpurl}" width="80px" height="80px">
			<h1>${username}'s profile</h1>
			<p>${bio}</p>
			<hr>
			<h1>Posts</h1>
		</div>
	</body>
</html>

Add information about the minimum node version

With jsdom 20, there is a minimum node version dependency which is specified in the jsdom package.json, but it seems the engines property is not taken into account for transitive dependencies and hence npm i does not fail on the consumer of isomorphic-dompurify, but at runtime it throws an error

Might make sense to mention this in the readme / troubleshooting somewhere

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.