Commit f58ce22f authored by Paul Gascou-Vaillancourt's avatar Paul Gascou-Vaillancourt Committed by Phil Hughes

Wrap file paths in vulnerability details modal

Use gitlab-ui's FriendlyWrap component to properly wrap file paths
in the vulnerability details modal
parent a5aec1d0
<script>
import { GlFriendlyWrap } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import SafeLink from 'ee/vue_shared/components/safe_link.vue';
import SeverityBadge from './severity_badge.vue';
......@@ -6,6 +7,7 @@ import SeverityBadge from './severity_badge.vue';
export default {
name: 'VulnerabilityDetails',
components: {
GlFriendlyWrap,
Icon,
SafeLink,
SeverityBadge,
......@@ -23,17 +25,17 @@ export default {
hasValue(field) {
return field.value && field.value.length > 0;
},
hasInstances(field, key) {
return key === 'instances' && this.hasValue(field);
hasInstances(key) {
return key === 'instances';
},
hasIdentifiers(field, key) {
return key === 'identifiers' && this.hasValue(field);
hasIdentifiers(key) {
return key === 'identifiers';
},
hasLinks(field, key) {
return key === 'links' && this.hasValue(field);
hasLinks(key) {
return key === 'links';
},
hasSeverity(field, key) {
return key === 'severity' && this.hasValue(field);
hasSeverity(key) {
return key === 'severity';
},
},
};
......@@ -44,81 +46,85 @@ export default {
<div v-for="(field, key, index) in details" :key="index" class="d-flex my-2">
<label class="col-2 text-right font-weight-bold pl-0">{{ field.text }}:</label>
<div class="col-10 pl-0 text-secondary">
<div v-if="hasInstances(field, key)" class="info-well">
<ul class="report-block-list">
<li v-for="(instance, i) in field.value" :key="i" class="report-block-list-issue">
<div class="report-block-list-icon append-right-5 failed">
<icon :size="32" name="status_failed_borderless" />
</div>
<div class="report-block-list-issue-description prepend-top-5 append-bottom-5">
<div class="report-block-list-issue-description-text">
{{ instance.method }}
<template v-if="hasValue(field)">
<div v-if="hasInstances(key)" class="info-well">
<ul class="report-block-list">
<li v-for="(instance, i) in field.value" :key="i" class="report-block-list-issue">
<div class="report-block-list-icon append-right-5 failed">
<icon :size="32" name="status_failed_borderless" />
</div>
<div class="report-block-list-issue-description-link">
<safe-link
:href="instance.uri"
target="_blank"
rel="noopener noreferrer nofollow"
class="break-link"
>
{{ instance.uri }}
</safe-link>
<div class="report-block-list-issue-description prepend-top-5 append-bottom-5">
<div class="report-block-list-issue-description-text">
{{ instance.method }}
</div>
<div class="report-block-list-issue-description-link">
<safe-link
:href="instance.uri"
target="_blank"
rel="noopener noreferrer nofollow"
class="break-link"
>
{{ instance.uri }}
</safe-link>
</div>
<expand-button v-if="instance.evidence">
<pre
slot="expanded"
class="block report-block-dast-code prepend-top-10 report-block-issue-code"
>
{{ instance.evidence }}</pre
>
</expand-button>
</div>
<expand-button v-if="instance.evidence">
<pre
slot="expanded"
class="block report-block-dast-code prepend-top-10 report-block-issue-code"
>
{{ instance.evidence }}</pre
>
</expand-button>
</div>
</li>
</ul>
</div>
<template v-else-if="hasIdentifiers(field, key)">
<span v-for="(identifier, i) in field.value" :key="i">
</li>
</ul>
</div>
<template v-else-if="hasIdentifiers(key)">
<span v-for="(identifier, i) in field.value" :key="i">
<safe-link
v-if="identifier.url"
:class="`js-link-${key}`"
:href="identifier.url"
target="_blank"
rel="noopener noreferrer"
>
{{ identifier.name }}
</safe-link>
<span v-else> {{ identifier.name }} </span>
<span v-if="hasMoreValues(i, field.value)">,&nbsp;</span>
</span>
</template>
<template v-else-if="hasLinks(key)">
<span v-for="(link, i) in field.value" :key="i">
<safe-link
:class="`js-link-${key}`"
:href="link.url"
target="_blank"
rel="noopener noreferrer"
>
{{ link.value || link.url }}
</safe-link>
<span v-if="hasMoreValues(i, field.value)">,&nbsp;</span>
</span>
</template>
<template v-else-if="hasSeverity(key)">
<severity-badge :severity="field.value" class="d-inline" />
</template>
<template v-else>
<safe-link
v-if="identifier.url"
v-if="field.isLink"
:class="`js-link-${key}`"
:href="identifier.url"
:href="field.url"
target="_blank"
rel="noopener noreferrer"
>
{{ identifier.name }}
<gl-friendly-wrap :text="field.value" />
</safe-link>
<span v-else> {{ identifier.name }} </span>
<span v-if="hasMoreValues(i, field.value)">,&nbsp;</span>
</span>
</template>
<template v-else-if="hasLinks(field, key)">
<span v-for="(link, i) in field.value" :key="i">
<safe-link
:class="`js-link-${key}`"
:href="link.url"
target="_blank"
rel="noopener noreferrer"
>
{{ link.value || link.url }}
</safe-link>
<span v-if="hasMoreValues(i, field.value)">,&nbsp;</span>
</span>
</template>
<template v-else-if="hasSeverity(field, key)">
<severity-badge :severity="field.value" class="d-inline" />
</template>
<template v-else>
<safe-link
v-if="field.isLink"
:class="`js-link-${key}`"
:href="field.url"
target="_blank"
>
{{ field.value }}
</safe-link>
<span v-else :class="{ 'text-capitalize': key === 'confidence' }">
{{ field.value }}
</span>
<gl-friendly-wrap
v-else
:text="field.value"
:class="{ 'text-capitalize': key === 'confidence' }"
/>
</template>
</template>
</div>
</div>
......
---
title: Prevent files paths from overflowing in vulnerability info modal
merge_request: 10606
author:
type: fixed
import { createLocalVue, shallowMount } from '@vue/test-utils';
import { createLocalVue, mount } from '@vue/test-utils';
import createState from 'ee/vue_shared/security_reports/store/state';
import VulnerabilityDetails from 'ee/vue_shared/security_reports/components/vulnerability_details.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
......@@ -10,7 +10,7 @@ describe('VulnerabilityDetails component', () => {
const localVue = createLocalVue();
const componentFactory = (options = {}) => {
wrapper = shallowMount(localVue.extend(VulnerabilityDetails), {
wrapper = mount(localVue.extend(VulnerabilityDetails), {
...options,
localVue,
sync: false,
......@@ -48,6 +48,34 @@ describe('VulnerabilityDetails component', () => {
});
});
it('renders wrapped file paths', () => {
const value = '/some/file/path';
const valueWrapped = '/<wbr>some/<wbr>file/<wbr>path';
const details = {
file: {
value,
url: `${TEST_HOST}/bar`,
isLink: true,
},
};
componentFactory({ propsData: { details } });
expect(wrapper.find(SafeLink).html()).toMatch(valueWrapped);
});
it('escapes wrapped file paths', () => {
const value = '/unsafe/path<script></script>';
const valueWrapped = '/<wbr>unsafe/<wbr>path&lt;script&gt;&lt;/<wbr>script&gt;';
const details = {
file: {
value,
url: `${TEST_HOST}/bar`,
isLink: true,
},
};
componentFactory({ propsData: { details } });
expect(wrapper.find(SafeLink).html()).toMatch(valueWrapped);
});
describe('does not render XSS links', () => {
// eslint-disable-next-line no-script-url
const badUrl = 'javascript:alert("")';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment