diff --git a/package-lock.json b/package-lock.json index b86cd7577..58f12cffe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35327,12 +35327,6 @@ "integrity": "sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ==", "dev": true }, - "node_modules/@types/is-url": { - "version": "1.2.32", - "resolved": "https://registry.npmjs.org/@types/is-url/-/is-url-1.2.32.tgz", - "integrity": "sha512-46VLdbWI8Sc+hPexQ6NLNR2YpoDyDZIpASHkJQ2Yr+Kf9Giw6LdCTkwOdsnHKPQeh7xTjTmSnxbE8qpxYuCiHA==", - "dev": true - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", @@ -35803,6 +35797,12 @@ "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", "dev": true }, + "node_modules/@types/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==", + "dev": true + }, "node_modules/@types/video.js": { "version": "7.3.52", "integrity": "sha512-WFj/HkNVCfkchXDeDU0QbimC356FB5vva3g5mgsjk8n3UMKqP9S522rQAmu9LGPiCmShZRPuAlkXmbp5WId6ow==", @@ -48435,11 +48435,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" - }, "node_modules/is-utf8": { "version": "0.2.1", "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", @@ -72083,8 +72078,8 @@ "@tanstack/react-query": "^4.29.15", "aws-sdk-client-mock": "^3.0.0", "buffer": "^6.0.3", + "dompurify": "^3.1.6", "is-hotkey": "^0.2.0", - "is-url": "^1.2.4", "papaparse": "^5.4.1", "parse-duration": "^1.0.3", "react-dnd": "^16.0.1", @@ -72098,7 +72093,8 @@ "react-use": "17.4.0", "tiny-invariant": "^1.3.1", "turbowatch": "^2.29.4", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "validator": "^13.12.0" }, "devDependencies": { "@faker-js/faker": "^8.2.0", @@ -72125,12 +72121,12 @@ "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", "@types/is-hotkey": "^0.1.7", - "@types/is-url": "^1.2.32", "@types/lodash": "^4.14.195", "@types/node": "^18.16.18", "@types/papaparse": "^5.3.10", "@types/react": "^18.2.12", "@types/react-dom": "^18.2.5", + "@types/validator": "^13.12.0", "css-loader": "6.8.1", "dotenv": "^16.3.1", "eslint-config-iot-app-kit": "10.10.1", @@ -72437,6 +72433,11 @@ "node": ">=12" } }, + "packages/dashboard/node_modules/dompurify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==" + }, "packages/dashboard/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -72880,6 +72881,14 @@ "uuid": "dist/bin/uuid" } }, + "packages/dashboard/node_modules/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", + "engines": { + "node": ">= 0.10" + } + }, "packages/dashboard/node_modules/w3c-xmlserializer": { "version": "4.0.0", "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", @@ -92542,20 +92551,20 @@ "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", "@types/is-hotkey": "^0.1.7", - "@types/is-url": "^1.2.32", "@types/lodash": "^4.14.195", "@types/node": "^18.16.18", "@types/papaparse": "^5.3.10", "@types/react": "^18.2.12", "@types/react-dom": "^18.2.5", + "@types/validator": "^13.12.0", "aws-sdk-client-mock": "^3.0.0", "buffer": "^6.0.3", "css-loader": "6.8.1", + "dompurify": "^3.1.6", "dotenv": "^16.3.1", "eslint-config-iot-app-kit": "10.10.1", "eslint-plugin-jsx-a11y": "^6.8.0", "is-hotkey": "^0.2.0", - "is-url": "^1.2.4", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "jest-extended": "^3.2.4", @@ -92597,6 +92606,7 @@ "turbowatch": "^2.29.4", "typescript": "^4.9.5", "uuid": "^9.0.0", + "validator": "^13.12.0", "webpack": "^5.88.2" }, "dependencies": { @@ -92784,6 +92794,11 @@ "webidl-conversions": "^7.0.0" } }, + "dompurify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", + "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==" + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -93118,6 +93133,11 @@ "version": "9.0.0", "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, + "validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==" + }, "w3c-xmlserializer": { "version": "4.0.0", "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", @@ -114272,12 +114292,6 @@ "integrity": "sha512-yB5C7zcOM7idwYZZ1wKQ3pTfjA9BbvFqRWvKB46GFddxnJtHwi/b9y84ykQtxQPg5qhdpg4Q/kWU3EGoCTmLzQ==", "dev": true }, - "@types/is-url": { - "version": "1.2.32", - "resolved": "https://registry.npmjs.org/@types/is-url/-/is-url-1.2.32.tgz", - "integrity": "sha512-46VLdbWI8Sc+hPexQ6NLNR2YpoDyDZIpASHkJQ2Yr+Kf9Giw6LdCTkwOdsnHKPQeh7xTjTmSnxbE8qpxYuCiHA==", - "dev": true - }, "@types/istanbul-lib-coverage": { "version": "2.0.4", "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", @@ -114723,6 +114737,12 @@ "integrity": "sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ==", "dev": true }, + "@types/validator": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==", + "dev": true + }, "@types/video.js": { "version": "7.3.52", "integrity": "sha512-WFj/HkNVCfkchXDeDU0QbimC356FB5vva3g5mgsjk8n3UMKqP9S522rQAmu9LGPiCmShZRPuAlkXmbp5WId6ow==", @@ -123812,11 +123832,6 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, - "is-url": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==" - }, "is-utf8": { "version": "0.2.1", "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", diff --git a/packages/dashboard/package.json b/packages/dashboard/package.json index d3c69b727..d767dd66a 100644 --- a/packages/dashboard/package.json +++ b/packages/dashboard/package.json @@ -60,12 +60,12 @@ "@testing-library/react": "^14.0.0", "@testing-library/user-event": "^14.4.3", "@types/is-hotkey": "^0.1.7", - "@types/is-url": "^1.2.32", "@types/lodash": "^4.14.195", "@types/node": "^18.16.18", "@types/papaparse": "^5.3.10", "@types/react": "^18.2.12", "@types/react-dom": "^18.2.5", + "@types/validator": "^13.12.0", "css-loader": "6.8.1", "dotenv": "^16.3.1", "eslint-config-iot-app-kit": "10.10.1", @@ -110,8 +110,8 @@ "@tanstack/react-query": "^4.29.15", "aws-sdk-client-mock": "^3.0.0", "buffer": "^6.0.3", + "dompurify": "^3.1.6", "is-hotkey": "^0.2.0", - "is-url": "^1.2.4", "papaparse": "^5.4.1", "parse-duration": "^1.0.3", "react-dnd": "^16.0.1", @@ -125,7 +125,8 @@ "react-use": "17.4.0", "tiny-invariant": "^1.3.1", "turbowatch": "^2.29.4", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "validator": "^13.12.0" }, "peerDependencies": { "@aws-sdk/client-iot-events": "^3.354.0", diff --git a/packages/dashboard/src/customization/widgets/text/link/index.tsx b/packages/dashboard/src/customization/widgets/text/link/index.tsx index 0089640dc..426471711 100644 --- a/packages/dashboard/src/customization/widgets/text/link/index.tsx +++ b/packages/dashboard/src/customization/widgets/text/link/index.tsx @@ -2,7 +2,8 @@ import type { CSSProperties } from 'react'; import React from 'react'; import { defaultFontSettings } from '../styledText/defaultFontSettings'; import type { TextWidget } from '../../types'; -import isValidUrl from 'is-url'; +import DOMPurify from 'dompurify'; +import { isURL } from 'validator'; type TextLinkProps = TextWidget; @@ -23,7 +24,9 @@ const TextLink: React.FC = (widget) => { color: fontColor, }; - const renderedHref = href && isValidUrl(href) ? href : undefined; + const sanitizedHref = href ? DOMPurify.sanitize(href) : undefined; + const isValidUrl = sanitizedHref ? isURL(sanitizedHref) : false; + const renderedHref = isValidUrl ? sanitizedHref : undefined; return (