]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-17579 UI changes to open external links from user input in a new tab
authorRevanshu Paliwal <revanshu.paliwal@sonarsource.com>
Fri, 16 Dec 2022 15:03:03 +0000 (16:03 +0100)
committersonartech <sonartech@sonarsource.com>
Mon, 19 Dec 2022 20:02:46 +0000 (20:02 +0000)
server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsDescription.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotReviewHistory.tsx
server/sonar-web/src/main/js/apps/sessions/components/Login.tsx
server/sonar-web/src/main/js/apps/settings/components/inputs/InputForFormattedText.tsx
server/sonar-web/src/main/js/components/issue/components/IssueCommentLine.tsx
server/sonar-web/src/main/js/components/issue/popups/CommentTile.tsx
server/sonar-web/src/main/js/helpers/sanitize.ts

index 795a6b0e6c35957c0d22e4ccbec69ebcd7310663..724ebbaceb045deca77fc9ea8b85cfac75adb6b1 100644 (file)
@@ -23,7 +23,7 @@ import FormattingTips from '../../../components/common/FormattingTips';
 import { Button, ResetButtonLink } from '../../../components/controls/buttons';
 import RuleTabViewer from '../../../components/rules/RuleTabViewer';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { sanitizeString } from '../../../helpers/sanitize';
+import { sanitizeString, sanitizeUserInput } from '../../../helpers/sanitize';
 import { RuleDetails } from '../../../types/types';
 import { RuleDescriptionSections } from '../rule';
 import RemoveExtendedDescriptionModal from './RemoveExtendedDescriptionModal';
@@ -115,7 +115,9 @@ export default class RuleDetailsDescription extends React.PureComponent<Props, S
         <div
           className="rule-desc spacer-bottom markdown"
           // eslint-disable-next-line react/no-danger
-          dangerouslySetInnerHTML={{ __html: sanitizeString(this.props.ruleDetails.htmlNote) }}
+          dangerouslySetInnerHTML={{
+            __html: sanitizeUserInput(this.props.ruleDetails.htmlNote),
+          }}
         />
       )}
       {this.props.canWrite && (
index 87a55a8b3727837d07ddb8d49a67b253e79e75bc..6f9754d44b12632e53ce8b0a406e56d7fbb0c56a 100644 (file)
@@ -27,7 +27,7 @@ import IssueChangelogDiff from '../../../components/issue/components/IssueChange
 import Avatar from '../../../components/ui/Avatar';
 import { PopupPlacement } from '../../../components/ui/popups';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { sanitizeString } from '../../../helpers/sanitize';
+import { sanitizeUserInput } from '../../../helpers/sanitize';
 import { Hotspot, ReviewHistoryType } from '../../../types/security-hotspots';
 import { getHotspotReviewHistory } from '../utils';
 import HotspotCommentPopup from './HotspotCommentPopup';
@@ -106,7 +106,7 @@ export default function HotspotReviewHistory(props: HotspotReviewHistoryProps) {
                   <div
                     className="markdown"
                     // eslint-disable-next-line react/no-danger
-                    dangerouslySetInnerHTML={{ __html: sanitizeString(html) }}
+                    dangerouslySetInnerHTML={{ __html: sanitizeUserInput(html) }}
                   />
                   {updatable && (
                     <div>
index 107dc765de76e8335fe27c6a0e3752eab061f94a..80a6e83c51592231e22dba56dd98deb7484b1124 100644 (file)
@@ -22,7 +22,7 @@ import { Location } from '../../../components/hoc/withRouter';
 import { Alert } from '../../../components/ui/Alert';
 import DeferredSpinner from '../../../components/ui/DeferredSpinner';
 import { translate } from '../../../helpers/l10n';
-import { sanitizeString } from '../../../helpers/sanitize';
+import { sanitizeUserInput } from '../../../helpers/sanitize';
 import { getReturnUrl } from '../../../helpers/urls';
 import { IdentityProvider } from '../../../types/types';
 import './Login.css';
@@ -62,7 +62,7 @@ export default function Login(props: LoginProps) {
             <div
               className="login-message markdown big-padded spacer-top huge-spacer-bottom"
               // eslint-disable-next-line react/no-danger
-              dangerouslySetInnerHTML={{ __html: sanitizeString(message) }}
+              dangerouslySetInnerHTML={{ __html: sanitizeUserInput(message) }}
             />
           )}
 
index 6af35c4f0b224b92469d646aba257afffcbf5e51..0acda77c787f3e2a3788fd5e07c638385b773062 100644 (file)
@@ -22,7 +22,7 @@ import FormattingTipsWithLink from '../../../../components/common/FormattingTips
 import { Button } from '../../../../components/controls/buttons';
 import EditIcon from '../../../../components/icons/EditIcon';
 import { translate } from '../../../../helpers/l10n';
-import { sanitizeString } from '../../../../helpers/sanitize';
+import { sanitizeUserInput } from '../../../../helpers/sanitize';
 import { DefaultSpecializedInputProps } from '../../utils';
 
 export default function InputForFormattedText(props: DefaultSpecializedInputProps) {
@@ -54,7 +54,7 @@ export default function InputForFormattedText(props: DefaultSpecializedInputProp
           <div
             className="markdown-preview markdown"
             // eslint-disable-next-line react/no-danger
-            dangerouslySetInnerHTML={{ __html: sanitizeString(formattedValue ?? '') }}
+            dangerouslySetInnerHTML={{ __html: sanitizeUserInput(formattedValue ?? '') }}
           />
           <Button className="spacer-top" onClick={props.onEditing}>
             <EditIcon className="spacer-right" />
index 8cd3cd98ad525216bce3e23b478cd6e741a1f46c..ae6ed0d32dcf117b373c4f5df4cc97b5dde25e2e 100644 (file)
@@ -22,7 +22,7 @@ import { DeleteButton, EditButton } from '../../../components/controls/buttons';
 import Toggler from '../../../components/controls/Toggler';
 import { PopupPlacement } from '../../../components/ui/popups';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { sanitizeString } from '../../../helpers/sanitize';
+import { sanitizeUserInput } from '../../../helpers/sanitize';
 import { IssueComment } from '../../../types/types';
 import DateFromNow from '../../intl/DateFromNow';
 import Avatar from '../../ui/Avatar';
@@ -98,7 +98,7 @@ export default class IssueCommentLine extends React.PureComponent<Props, State>
         <div
           className="issue-comment-text markdown"
           // eslint-disable-next-line react/no-danger
-          dangerouslySetInnerHTML={{ __html: sanitizeString(comment.htmlText) }}
+          dangerouslySetInnerHTML={{ __html: sanitizeUserInput(comment.htmlText) }}
         />
         <div className="issue-comment-age">
           <span className="a11y-hidden">{translate('issue.comment.posted_on')}</span>
index 6388aca9d64ff6e981c94fd48f7271d686d7f360..8c02f495b413f7148823e17f139ca58c3d91aa26 100644 (file)
@@ -19,7 +19,7 @@
  */
 import * as React from 'react';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { sanitizeString } from '../../../helpers/sanitize';
+import { sanitizeUserInput } from '../../../helpers/sanitize';
 import { IssueComment } from '../../../types/types';
 import { DeleteButton, EditButton } from '../../controls/buttons';
 import DateTimeFormatter from '../../intl/DateTimeFormatter';
@@ -84,7 +84,7 @@ export default class CommentTile extends React.PureComponent<CommentTileProps, C
             <div
               className="flex-1 markdown"
               // eslint-disable-next-line react/no-danger
-              dangerouslySetInnerHTML={{ __html: sanitizeString(comment.htmlText) }}
+              dangerouslySetInnerHTML={{ __html: sanitizeUserInput(comment.htmlText) }}
             />
           )}
           {showEditArea && (
index 75cb96e84f5fb526412f088febb23988f5e33958..007104385bc4b3b89822920e95e411a0c53b1df9 100644 (file)
@@ -29,3 +29,29 @@ export function sanitizeStringRestricted(html: string) {
 export function sanitizeString(html: string) {
   return sanitize(html, { USE_PROFILES: { html: true } });
 }
+
+export function sanitizeUserInput(html: string) {
+  return sanitize(html, {
+    ALLOWED_TAGS: [
+      'b',
+      'br',
+      'code',
+      'i',
+      'li',
+      'p',
+      'strong',
+      'ul',
+      'ol',
+      'a',
+      'h1',
+      'h2',
+      'h3',
+      'h4',
+      'h5',
+      'h6',
+      'blockquote',
+      'pre',
+    ],
+    ALLOWED_ATTR: ['target', 'href'],
+  });
+}