Skip to content

Commit

Permalink
Merge pull request #2833 from plotly/fix/xss-data-url
Browse files Browse the repository at this point in the history
Allow data urls
  • Loading branch information
T4rk1n committed Apr 22, 2024
2 parents 0d96c02 + 30e2755 commit 9a4a479
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 186 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## Fixed

- [#2362](https://github.com/plotly/dash/pull/2362) Global namespace not polluted any more when loading clientside callbacks.
- [#2833](https://github.com/plotly/dash/pull/2833) Allow data url in link props. Fixes [#2764](https://github.com/plotly/dash/issues/2764)

## [2.16.1] - 2024-03-06

Expand Down
11 changes: 0 additions & 11 deletions components/dash-core-components/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions components/dash-core-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
"maintainer": "Alex Johnson <alex@plotly.com>",
"license": "MIT",
"dependencies": {
"@braintree/sanitize-url": "^7.0.0",
"@fortawesome/fontawesome-svg-core": "1.2.36",
"@fortawesome/free-regular-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
Expand Down Expand Up @@ -87,13 +86,15 @@
"react": "^16.14.0",
"react-dom": "^16.14.0",
"react-jsx-parser": "1.21.0",
"rimraf": "^5.0.5",
"style-loader": "^3.3.3",
"styled-jsx": "^3.4.4",
"webpack": "^5.90.3",
"webpack-cli": "^5.1.4",
"rimraf": "^5.0.5"
"webpack-cli": "^5.1.4"
},
"optionalDependencies": {
"fsevents": "*"
},
"optionalDependencies": { "fsevents": "*" },
"files": [
"/dash_core_components/*{.js,.map}",
"/lib/"
Expand Down
4 changes: 2 additions & 2 deletions components/dash-core-components/src/components/Link.react.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import PropTypes from 'prop-types';

import React, {useEffect, useMemo} from 'react';
import {sanitizeUrl} from '@braintree/sanitize-url';
import {isNil} from 'ramda';

/*
Expand Down Expand Up @@ -46,8 +45,9 @@ const Link = props => {
refresh,
setProps,
} = props;
const cleanUrl = window.dash_clientside.clean_url;
const sanitizedUrl = useMemo(() => {
return href ? sanitizeUrl(href) : undefined;
return href ? cleanUrl(href) : undefined;
}, [href]);

const updateLocation = e => {
Expand Down
11 changes: 0 additions & 11 deletions components/dash-html-components/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 5 additions & 6 deletions components/dash-html-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
"author": "Chris Parmer <chris@plotly.com>",
"maintainer": "Alex Johnson <alex@plotly.com>",
"dependencies": {
"@braintree/sanitize-url": "^7.0.0",
"prop-types": "^15.8.1",
"ramda": "^0.29.0"
},
Expand All @@ -44,16 +43,16 @@
"eslint": "^8.41.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-react": "^7.32.2",
"mkdirp": "^0.5.1",
"npm-run-all": "^4.1.5",
"react": "^16.14.0",
"react-docgen": "^5.4.3",
"react-dom": "^16.14.0",
"request": "^2.88.2",
"rimraf": "^5.0.5",
"string": "^3.3.3",
"webpack": "^5.90.3",
"webpack-cli": "^5.1.4",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"rimraf": "^5.0.5",
"mkdirp": "^0.5.1"
"webpack-cli": "^5.1.4"
},
"files": [
"/dash_html_components/*{.js,.map}"
Expand Down
12 changes: 3 additions & 9 deletions components/dash-html-components/scripts/generate-components.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,18 +249,12 @@ const customDocs = {
* <body>.`
};

const customImportsForComponents = {
a: `import {sanitizeUrl} from '@braintree/sanitize-url';`,
form: `import {sanitizeUrl} from '@braintree/sanitize-url';`,
iframe: `import {sanitizeUrl} from '@braintree/sanitize-url';`,
object: `import {sanitizeUrl} from '@braintree/sanitize-url';`,
embed: `import {sanitizeUrl} from '@braintree/sanitize-url';`,
button: `import {sanitizeUrl} from '@braintree/sanitize-url';`,
}
const customImportsForComponents = {};

function createXSSProtection(propName) {
return `
const ${propName} = React.useMemo(() => props.${propName} && sanitizeUrl(props.${propName}), [props.${propName}]);
const cleanUrl = window.dash_clientside.clean_url;
const ${propName} = React.useMemo(() => props.${propName} && cleanUrl(props.${propName}), [props.${propName}]);
if (${propName}) {
extraProps.${propName} = ${propName};
Expand Down
25 changes: 25 additions & 0 deletions dash/dash-renderer/src/utils/clientsideFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,31 @@ const set_props = (id: string | object, props: {[k: string]: any}) => {
}
};

// Clean url code adapted from https://github.com/braintree/sanitize-url/blob/main/src/constants.ts
// to allow for data protocol.
const invalidProtocols = /^([^\w]*)(javascript|vbscript)/im;
const newLines = /&(tab|newline);/gi;

// eslint-disable-next-line no-control-regex
const ctrlChars = /[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim;
const htmlEntities = /&#(\w+)(^\w|;)?/g;

const clean_url = (url: string, fallback = 'about:blank') => {
if (url === '') {
return url;
}
const cleaned = url
.replace(newLines, '')
.replace(ctrlChars, '')
.replace(htmlEntities, (_, dec) => String.fromCharCode(dec))
.trim();
if (invalidProtocols.test(cleaned)) {
return fallback;
}
return url;
};

const dc = ((window as any).dash_clientside =
(window as any).dash_clientside || {});
dc['set_props'] = set_props;
dc['clean_url'] = dc['clean_url'] === undefined ? clean_url : dc['clean_url'];
Loading

0 comments on commit 9a4a479

Please sign in to comment.