kkomelin / isomorphic-dompurify Goto Github PK
View Code? Open in Web Editor NEWUse DOMPurify on server and client in the same way
License: MIT License
Use DOMPurify on server and client in the same way
License: MIT License
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
https://github.com/marketplace/dependabot-preview
Dependabot is a free tool that can be installed onto this repo which will automatically open pull requests when a dependency is out of date. Adding this integration will make it easy to keep up to date with DOMPurify updates.
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.
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.
Add to next.config.js
:
module.exports = {
target: 'serverless'
}
Run next build
This issue could be related to #35 , but i don't use umijs.
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
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.
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"
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.
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<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></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=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href='᠎javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href='​javascript:alert(1)'>CLICK</a><a href=' javascript:alert(1)'>CLICK</a><a href=' 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?
My suggestions are:
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
<html lang="en">
<head>
<title>Sample HTML5 Page</title>
</head>
<body>
<p>Hello</p>
<br>
</body>
</html>
Empty string
<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
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:
function r(m){return m && m.default || m;}
returns the default export if available, else just whatever m
is (i.e. a module)global.DOMPurify
if it exists (meaning global
exists, meaning we're in node
)... ortypeof 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, elsenode
, 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'
DOMPurify public methods are defined here: https://github.com/cure53/DOMPurify/blob/master/src/purify.js
Examples of type definition files:
Hi, i'm trying to use your lib in my own components library and then import it in Next.js. Everything works in my library but in the Next integration it causes some missing errors
Module not found: Can't resolve 'fs'
Module not found: Can't resolve 'child_process'
Module not found: Can't resolve 'net'
Module not found: Can't resolve 'tls'
Module not found: Can't resolve './xhr-sync-worker.js'
....
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?
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.
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",
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.
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)
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
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
As @NicholasEllul suggested, we could copy DOMPurify versions if DOMPurify maintainers would agree to use semantic versioning.
The idea is to only mirror major and minor versions of DOMPurify. The patch segment would be reserved for our own bug fixes.
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>
Re: cure53/DOMPurify#691 (comment)
it may be a good step forward to join forces and merge the isomorphic-dompurify
changes with the parent project dompurify
Open to advice/ideas on how to better implement it.
We see a high amount of CPU Utilisation by this package in our application. Can you please explain why is it so.
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.
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:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.