Skip to content

Commit

Permalink
SONAR-23741 Backport fixes for SSF-656 & SSF-657
Browse files Browse the repository at this point in the history
  • Loading branch information
david-cho-lerat-sonarsource authored and sonartech committed Nov 25, 2024
1 parent 2ac9033 commit 43af64d
Show file tree
Hide file tree
Showing 37 changed files with 930 additions and 715 deletions.
24 changes: 23 additions & 1 deletion server/sonar-web/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,29 @@
"rules": {
"camelcase": "off",
"promise/no-return-wrap": "warn",
"react/forbid-component-props": [
"error",
{
"forbid": [
{
"propName": "dangerouslySetInnerHTML",
"message": "Use the SafeHTMLInjection component instead of 'dangerouslySetInnerHTML', to prevent CSS injection along other XSS attacks"
}
]
}
],
"react/forbid-dom-props": [
"error",
{
"forbid": [
{
"propName": "dangerouslySetInnerHTML",
"message": "Use the SafeHTMLInjection component instead of 'dangerouslySetInnerHTML', to prevent CSS injection along other XSS attacks"
}
]
}
],
"react/jsx-curly-brace-presence": "warn",
"testing-library/render-result-naming-convention": "off"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import { FormattedMessage } from 'react-intl';
import NotFound from '../../../app/components/NotFound';
import A11ySkipTarget from '../../../components/a11y/A11ySkipTarget';
Expand Down Expand Up @@ -103,7 +104,7 @@ import {
postJSONBody,
request,
} from '../../../helpers/request';
import { sanitizeStringRestricted } from '../../../helpers/sanitize';
import { sanitizeHTMLRestricted } from '../../../helpers/sanitize';
import {
getStandards,
renderCWECategory,
Expand Down Expand Up @@ -166,7 +167,7 @@ const exposeLibraries = () => {
getComponentSecurityHotspotsUrl,
getMeasureHistoryUrl,
getRulesUrl,
sanitizeStringRestricted,
sanitizeStringRestricted: sanitizeHTMLRestricted,
};
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import * as React from 'react';
import Link from '../../../components/common/Link';
import ClockIcon from '../../../components/icons/ClockIcon';
import FavoriteIcon from '../../../components/icons/FavoriteIcon';
import QualifierIcon from '../../../components/icons/QualifierIcon';
import { SafeHTMLInjection } from '../../../helpers/sanitize';
import { getComponentOverviewUrl } from '../../../helpers/urls';
import { ComponentResult } from './utils';

Expand Down Expand Up @@ -60,12 +62,9 @@ export default class SearchResult extends React.PureComponent<Props> {
</span>

{component.match ? (
<span
className="navbar-search-item-match"
// Safe: comes from the search engine, that injects bold tags into component names
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: component.match }}
/>
<SafeHTMLInjection htmlAsString={component.match}>
<span className="navbar-search-item-match" />
</SafeHTMLInjection>
) : (
<span className="navbar-search-item-match">{component.name}</span>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,13 @@ exports[`renders match 1`] = `
qualifier="TRK"
/>
</span>
<span
className="navbar-search-item-match"
dangerouslySetInnerHTML={
{
"__html": "f<mark>o</mark>o",
}
}
/>
<SafeHTMLInjection
htmlAsString="f<mark>o</mark>o"
>
<span
className="navbar-search-item-match"
/>
</SafeHTMLInjection>
</div>
<div
className="navbar-search-item-right text-muted-2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import classNames from 'classnames';
import * as React from 'react';
import { OptionTypeBase } from 'react-select';
Expand All @@ -26,7 +27,7 @@ import Modal from '../../../components/controls/Modal';
import Select from '../../../components/controls/Select';
import { Alert } from '../../../components/ui/Alert';
import { translate } from '../../../helpers/l10n';
import { sanitizeString } from '../../../helpers/sanitize';
import { SafeHTMLInjection, SanitizeLevel } from '../../../helpers/sanitize';
import { Dict, Rule, RuleActivation, RuleDetails } from '../../../types/types';
import { sortProfiles } from '../../quality-profiles/utils';
import { SeveritySelect } from './SeveritySelect';
Expand Down Expand Up @@ -218,11 +219,12 @@ export default class ActivationFormModal extends React.PureComponent<Props, Stat
/>
)}
{param.htmlDesc !== undefined && (
<div
className="note"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: sanitizeString(param.htmlDesc) }}
/>
<SafeHTMLInjection
htmlAsString={param.htmlDesc}
sanitizeLevel={SanitizeLevel.FORBID_SVG_MATHML}
>
<div className="note" />
</SafeHTMLInjection>
)}
</div>
))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import * as React from 'react';
import { components, OptionProps, OptionTypeBase, SingleValueProps } from 'react-select';
import { createRule, updateRule } from '../../../api/rules';
Expand All @@ -31,7 +32,7 @@ import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsEx
import { RULE_STATUSES, RULE_TYPES } from '../../../helpers/constants';
import { csvEscape } from '../../../helpers/csv';
import { translate } from '../../../helpers/l10n';
import { sanitizeString } from '../../../helpers/sanitize';
import { SafeHTMLInjection, SanitizeLevel } from '../../../helpers/sanitize';
import { latinize } from '../../../helpers/strings';
import { Dict, RuleDetails, RuleParameter } from '../../../types/types';
import { SeveritySelect } from './SeveritySelect';
Expand Down Expand Up @@ -317,11 +318,12 @@ export default class CustomRuleFormModal extends React.PureComponent<Props, Stat
/>
)}
{param.htmlDesc !== undefined && (
<div
className="modal-field-description"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: sanitizeString(param.htmlDesc) }}
/>
<SafeHTMLInjection
htmlAsString={param.htmlDesc}
sanitizeLevel={SanitizeLevel.FORBID_SVG_MATHML}
>
<div className="modal-field-description" />
</SafeHTMLInjection>
)}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import * as React from 'react';
import { updateRule } from '../../../api/rules';
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, sanitizeUserInput } from '../../../helpers/sanitize';
import { SafeHTMLInjection, SanitizeLevel } from '../../../helpers/sanitize';
import { RuleDetails } from '../../../types/types';
import { RuleDescriptionSections } from '../rule';
import RemoveExtendedDescriptionModal from './RemoveExtendedDescriptionModal';
Expand Down Expand Up @@ -112,14 +113,14 @@ export default class RuleDetailsDescription extends React.PureComponent<Props, S
renderExtendedDescription = () => (
<div id="coding-rules-detail-description-extra">
{this.props.ruleDetails.htmlNote !== undefined && (
<div
className="rule-desc spacer-bottom markdown"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: sanitizeUserInput(this.props.ruleDetails.htmlNote),
}}
/>
<SafeHTMLInjection
htmlAsString={this.props.ruleDetails.htmlNote}
sanitizeLevel={SanitizeLevel.USER_INPUT}
>
<div className="rule-desc spacer-bottom markdown" />
</SafeHTMLInjection>
)}

{this.props.canWrite && (
<Button
id="coding-rules-detail-extend-description"
Expand Down Expand Up @@ -216,23 +217,28 @@ export default class RuleDetailsDescription extends React.PureComponent<Props, S
return (
<div className="js-rule-description">
{defaultSection && (
<section
className="coding-rules-detail-description markdown"
key={defaultSection.key}
/* eslint-disable-next-line react/no-danger */
dangerouslySetInnerHTML={{ __html: sanitizeString(defaultSection.content) }}
/>
<SafeHTMLInjection
htmlAsString={defaultSection.content}
sanitizeLevel={SanitizeLevel.FORBID_SVG_MATHML}
>
<section
className="coding-rules-detail-description markdown"
key={defaultSection.key}
/>
</SafeHTMLInjection>
)}

{hasDescriptionSection && !defaultSection && (
<>
{introductionSection && (
<div
className="rule-desc"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: sanitizeString(introductionSection) }}
/>
<SafeHTMLInjection
htmlAsString={introductionSection}
sanitizeLevel={SanitizeLevel.FORBID_SVG_MATHML}
>
<div className="rule-desc" />
</SafeHTMLInjection>
)}

<RuleTabViewer ruleDetails={ruleDetails} />
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

import * as React from 'react';
import { translate } from '../../../helpers/l10n';
import { sanitizeString } from '../../../helpers/sanitize';
import { SafeHTMLInjection, SanitizeLevel } from '../../../helpers/sanitize';
import { RuleParameter } from '../../../types/types';

interface Props {
Expand All @@ -30,13 +31,17 @@ export default class RuleDetailsParameters extends React.PureComponent<Props> {
renderParameter = (param: RuleParameter) => (
<tr className="coding-rules-detail-parameter" key={param.key}>
<td className="coding-rules-detail-parameter-name">{param.key}</td>

<td className="coding-rules-detail-parameter-description">
{param.htmlDesc !== undefined && (
<p
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: sanitizeString(param.htmlDesc) }}
/>
<SafeHTMLInjection
htmlAsString={param.htmlDesc}
sanitizeLevel={SanitizeLevel.FORBID_SVG_MATHML}
>
<p />
</SafeHTMLInjection>
)}

{param.defaultValue !== undefined && (
<div className="note spacer-top">
{translate('coding_rules.parameters.default_value')}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,14 +160,14 @@ exports[`should render correctly: default 1`] = `
type="text"
value="1"
/>
<div
className="note"
dangerouslySetInnerHTML={
{
"__html": "description",
}
}
/>
<SafeHTMLInjection
htmlAsString="description"
sanitizeLevel={1}
>
<div
className="note"
/>
</SafeHTMLInjection>
</div>
<div
className="modal-field"
Expand Down Expand Up @@ -281,14 +281,14 @@ exports[`should render correctly: submitting 1`] = `
type="text"
value="1"
/>
<div
className="note"
dangerouslySetInnerHTML={
{
"__html": "description",
}
}
/>
<SafeHTMLInjection
htmlAsString="description"
sanitizeLevel={1}
>
<div
className="note"
/>
</SafeHTMLInjection>
</div>
<div
className="modal-field"
Expand Down Expand Up @@ -400,14 +400,14 @@ exports[`should render correctly: update mode 1`] = `
type="text"
value="1"
/>
<div
className="note"
dangerouslySetInnerHTML={
{
"__html": "description",
}
}
/>
<SafeHTMLInjection
htmlAsString="description"
sanitizeLevel={1}
>
<div
className="note"
/>
</SafeHTMLInjection>
</div>
<div
className="modal-field"
Expand Down Expand Up @@ -555,14 +555,14 @@ exports[`should render correctly: with deep profiles 1`] = `
type="text"
value="1"
/>
<div
className="note"
dangerouslySetInnerHTML={
{
"__html": "description",
}
}
/>
<SafeHTMLInjection
htmlAsString="description"
sanitizeLevel={1}
>
<div
className="note"
/>
</SafeHTMLInjection>
</div>
<div
className="modal-field"
Expand Down
Loading

0 comments on commit 43af64d

Please sign in to comment.