From 65e616ffa93f0e0029f792780ff8f3db0b830c2d Mon Sep 17 00:00:00 2001 From: Wouter Admiraal Date: Tue, 11 Dec 2018 08:35:04 +0100 Subject: SONAR-11506, SSF-62 Handle XSS code in project links --- .../src/main/js/apps/overview/meta/MetaLink.tsx | 55 ++++++++++++++++++---- .../apps/overview/meta/__tests__/MetaLink-test.tsx | 11 +++++ .../__tests__/__snapshots__/MetaLink-test.tsx.snap | 26 ++++++++-- .../sonar-web/src/main/js/apps/overview/styles.css | 17 +++++++ .../src/main/js/apps/projectLinks/LinkRow.tsx | 11 +++-- .../apps/projectLinks/__tests__/LinkRow-test.tsx | 11 +++++ .../__tests__/__snapshots__/LinkRow-test.tsx.snap | 49 ++++++++++++++++++- 7 files changed, 162 insertions(+), 18 deletions(-) (limited to 'server/sonar-web/src/main/js/apps') diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx index a1e1e6bad13..4c20250f881 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaLink.tsx @@ -20,18 +20,55 @@ import * as React from 'react'; import { getLinkName } from '../../projectLinks/utils'; import ProjectLinkIcon from '../../../components/icons-components/ProjectLinkIcon'; +import isValidUri from '../../../app/utils/isValidUri'; +import ClearIcon from '../../../components/icons-components/ClearIcon'; interface Props { link: T.ProjectLink; } -export default function MetaLink({ link }: Props) { - return ( -
  • - - - {getLinkName(link)} - -
  • - ); +interface State { + expanded: boolean; +} + +export default class MetaLink extends React.PureComponent { + state = { + expanded: false + }; + + handleClick = (event: React.MouseEvent) => { + event.preventDefault(); + this.setState(s => ({ expanded: !s.expanded })); + }; + + render() { + const { link } = this.props; + return ( +
  • + + + {getLinkName(link)} + + {this.state.expanded && ( +
    + ) => event.currentTarget.select()} + readOnly={true} + type="text" + value={link.url} + /> + + + +
    + )} +
  • + ); + } } diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.tsx b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.tsx index 0bea70841d8..23d0d3fa5eb 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaLink-test.tsx @@ -33,6 +33,17 @@ it('should match snapshot', () => { expect(shallow()).toMatchSnapshot(); }); +it('should render dangerous links as plaintext', () => { + const link = { + id: '1', + name: 'Dangerous', + url: 'javascript:alert("hi")', + type: 'dangerous' + }; + + expect(shallow()).toMatchSnapshot(); +}); + it('should expand and collapse link', () => { const link = { id: '1', diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.tsx.snap index 553a37c7bf1..a8f7dbb5bba 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaLink-test.tsx.snap @@ -5,7 +5,7 @@ exports[`should expand and collapse link 1`] = ` `; + +exports[`should render dangerous links as plaintext 1`] = ` +
  • + + + Dangerous + +
  • +`; diff --git a/server/sonar-web/src/main/js/apps/overview/styles.css b/server/sonar-web/src/main/js/apps/overview/styles.css index 06480c796cd..2ded3d250d6 100644 --- a/server/sonar-web/src/main/js/apps/overview/styles.css +++ b/server/sonar-web/src/main/js/apps/overview/styles.css @@ -470,6 +470,23 @@ background-color: transparent !important; } +.copy-paste-link .overview-key { + width: 90%; +} + +.copy-paste-link .close { + color: black; + border-bottom: 0; + height: 100%; + display: inline-block; + margin-left: 5px; + box-sizing: border-box; +} + +.copy-paste-link .close svg { + vertical-align: sub; +} + .overview-deleted-profile, .overview-deprecated-rules { margin: 4px -6px 4px; diff --git a/server/sonar-web/src/main/js/apps/projectLinks/LinkRow.tsx b/server/sonar-web/src/main/js/apps/projectLinks/LinkRow.tsx index 9ca2a8f6906..c3f83b718f6 100644 --- a/server/sonar-web/src/main/js/apps/projectLinks/LinkRow.tsx +++ b/server/sonar-web/src/main/js/apps/projectLinks/LinkRow.tsx @@ -23,6 +23,7 @@ import ConfirmButton from '../../components/controls/ConfirmButton'; import ProjectLinkIcon from '../../components/icons-components/ProjectLinkIcon'; import { Button } from '../../components/ui/buttons'; import { translate, translateWithParameters } from '../../helpers/l10n'; +import isValidUri from '../../app/utils/isValidUri'; interface Props { link: T.ProjectLink; @@ -90,9 +91,13 @@ export default class LinkRow extends React.PureComponent { {this.renderName(link)} - - {link.url} - + {isValidUri(link.url) ? ( + + {link.url} + + ) : ( + link.url + )} {this.renderDeleteButton(link)} diff --git a/server/sonar-web/src/main/js/apps/projectLinks/__tests__/LinkRow-test.tsx b/server/sonar-web/src/main/js/apps/projectLinks/__tests__/LinkRow-test.tsx index 19cff23dd62..3c93017c8ae 100644 --- a/server/sonar-web/src/main/js/apps/projectLinks/__tests__/LinkRow-test.tsx +++ b/server/sonar-web/src/main/js/apps/projectLinks/__tests__/LinkRow-test.tsx @@ -42,3 +42,14 @@ it('should render custom link', () => { ) ).toMatchSnapshot(); }); + +it('should render dangerous code as plain text', () => { + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/projectLinks/__tests__/__snapshots__/LinkRow-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectLinks/__tests__/__snapshots__/LinkRow-test.tsx.snap index c76c3e13aef..e05b8f94f91 100644 --- a/server/sonar-web/src/main/js/apps/projectLinks/__tests__/__snapshots__/LinkRow-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projectLinks/__tests__/__snapshots__/LinkRow-test.tsx.snap @@ -28,7 +28,7 @@ exports[`should render custom link 1`] = ` > http://example.com @@ -51,6 +51,51 @@ exports[`should render custom link 1`] = ` `; +exports[`should render dangerous code as plain text 1`] = ` + + +
    + +
    + + dangerous + +
    +
    + + + javascript:alert("Hello") + + + + + + + +`; + exports[`should render provided link 1`] = `
    http://example.com -- cgit v1.2.3