diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 9f477f5b7..e5192057f 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json @@ -543,7 +543,7 @@ "group_name": "Gruppenname", "grouped_vulnerabilities": "Gruppierte Schwachstellen", "hashes": "Hashwerte", - "hashes_short_desc": "Hash (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Hash", "home": "Heim", "id": "ID", "identifier": "Kennung", diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 1b9014eb3..9277b9bac 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -543,7 +543,7 @@ "group_name": "Group Name", "grouped_vulnerabilities": "Grouped Vulnerabilities", "hashes": "Hashes", - "hashes_short_desc": "Hash (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Hash", "home": "Home", "id": "ID", "identifier": "Identifier", diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index ff693e65d..557c0a6eb 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -543,7 +543,7 @@ "group_name": "Nombre del grupo", "grouped_vulnerabilities": "Vulnerabilidades agrupadas", "hashes": "hashes", - "hashes_short_desc": "Hash (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Hash", "home": "Hogar", "id": "ID", "identifier": "Identificador", diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index 06e5efebb..3a2987400 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -543,7 +543,7 @@ "group_name": "Nom de groupe", "grouped_vulnerabilities": "Vulnérabilités groupées", "hashes": "Condensats", - "hashes_short_desc": "Condensat (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Condensat", "home": "Accueil", "id": "ID", "identifier": "Identifiant", diff --git a/src/i18n/locales/hi.json b/src/i18n/locales/hi.json index 308e33c75..b5d658c96 100644 --- a/src/i18n/locales/hi.json +++ b/src/i18n/locales/hi.json @@ -543,7 +543,7 @@ "group_name": "समूह नाम", "grouped_vulnerabilities": "समूहीकृत कमज़ोरियाँ", "hashes": "हैश", - "hashes_short_desc": "हैश (MD5, SHA, SHA3, ब्लेक2b, ब्लेक3)", + "hashes_short_desc": "हैश", "home": "घर", "id": "आईडी", "identifier": "पहचानकर्ता", diff --git a/src/i18n/locales/it.json b/src/i18n/locales/it.json index 065342c10..e120969d2 100644 --- a/src/i18n/locales/it.json +++ b/src/i18n/locales/it.json @@ -543,7 +543,7 @@ "group_name": "Nome del gruppo", "grouped_vulnerabilities": "Vulnerabilità raggruppate", "hashes": "Hash", - "hashes_short_desc": "Hash (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Hash", "home": "Casa", "id": "ID", "identifier": "Identificatore", diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 1e934abed..5b27308ba 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -543,7 +543,7 @@ "group_name": "グループ名", "grouped_vulnerabilities": "グループ化された脆弱性", "hashes": "ハッシュ", - "hashes_short_desc": "ハッシュ (MD5、SHA、SHA3、Blake2b、Blake3)", + "hashes_short_desc": "ハッシュ", "home": "ホーム", "id": "ID", "identifier": "識別子", diff --git a/src/i18n/locales/pl.json b/src/i18n/locales/pl.json index 24a2ae3b2..e9ca59023 100644 --- a/src/i18n/locales/pl.json +++ b/src/i18n/locales/pl.json @@ -543,7 +543,7 @@ "group_name": "Nazwa grupy", "grouped_vulnerabilities": "Zgrupowane luki w zabezpieczeniach", "hashes": "Hasze", - "hashes_short_desc": "Hash (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Hash", "home": "Dom", "id": "ID", "identifier": "Identyfikator", diff --git a/src/i18n/locales/pt-BR.json b/src/i18n/locales/pt-BR.json index e9e237071..9cc909cbf 100644 --- a/src/i18n/locales/pt-BR.json +++ b/src/i18n/locales/pt-BR.json @@ -543,7 +543,7 @@ "group_name": "Nome do grupo", "grouped_vulnerabilities": "Vulnerabilidades agrupadas", "hashes": "Hashes", - "hashes_short_desc": "Hash (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Hash", "home": "Lar", "id": "ID", "identifier": "Identificador", diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 94f739c85..eddf92f5b 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -543,7 +543,7 @@ "group_name": "Nome do grupo", "grouped_vulnerabilities": "Vulnerabilidades agrupadas", "hashes": "Hashes", - "hashes_short_desc": "Hash (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Hash", "home": "Lar", "id": "ID", "identifier": "Identificador", diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 0cb8680da..cb5ea094a 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -543,7 +543,7 @@ "group_name": "Имя группы", "grouped_vulnerabilities": "Группированные уязвимости", "hashes": "Хэши", - "hashes_short_desc": "Хэш (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Хэш", "home": "Главная", "id": "ID", "identifier": "Идентификатор", diff --git a/src/i18n/locales/uk-UA.json b/src/i18n/locales/uk-UA.json index a3901a647..218c6d217 100644 --- a/src/i18n/locales/uk-UA.json +++ b/src/i18n/locales/uk-UA.json @@ -543,7 +543,7 @@ "group_name": "Назва групи", "grouped_vulnerabilities": "Згруповані вразливості", "hashes": "Хеші", - "hashes_short_desc": "Хеш (MD5, SHA, SHA3, Blake2b, Blake3)", + "hashes_short_desc": "Хеш", "home": "додому", "id": "ID", "identifier": "Ідентифікатор", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 203c3aaac..de5084c06 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -543,7 +543,7 @@ "group_name": "组名称", "grouped_vulnerabilities": "分组漏洞", "hashes": "哈希", - "hashes_short_desc": "哈希(MD5、SHA、SHA3、Blake2b、Blake3)", + "hashes_short_desc": "哈希", "home": "首页", "id": "ID", "identifier": "标识符", diff --git a/src/views/portfolio/components/ComponentSearch.vue b/src/views/portfolio/components/ComponentSearch.vue index 28d68b9b3..fbe34edca 100644 --- a/src/views/portfolio/components/ComponentSearch.vue +++ b/src/views/portfolio/components/ComponentSearch.vue @@ -13,7 +13,7 @@ + + + Select hash type + + + - {{ - $t('message.search') - }} + {{ $t('message.search') }} - - + :options="tableOptions" + /> @@ -73,6 +88,7 @@ import BInputGroupFormSelect from '../../../forms/BInputGroupFormSelect'; import BInputGroupFormInput from '../../../forms/BInputGroupFormInput'; import xssFilters from 'xss-filters'; import SeverityProgressBar from '@/views/components/SeverityProgressBar'; +import TokenPaginatedTable from '@/views/components/TokenPaginatedTable.vue'; import { loadUserPreferencesForBootstrapTable } from '@/shared/utils'; export default { @@ -82,6 +98,7 @@ export default { PortfolioWidgetRow, BInputGroupFormSelect, BInputGroupFormInput, + TokenPaginatedTable, }, beforeCreate() { this.subject = @@ -113,91 +130,104 @@ export default { } } this.changeSearchUrl = false; + this.$nextTick(() => { + if (!this.isSearchDisabled) { + this.performSearch(); + } + }); } }, watch: { + baseUrl(newVal) { + if (!newVal) return; + this.loadPage(newVal); + }, subject() { if (localStorage) { localStorage.setItem('ComponentSearchSubject', this.subject); + // Reset ALL inputs when subject changes. + this.value = null; + this.hashType = null; + this.coordinatesGroup = null; + this.coordinatesName = null; + this.coordinatesVersion = null; } }, }, + mounted() { + if (this.baseUrl) { + this.loadPage(this.baseUrl); + } + }, methods: { - createQueryParams: function () { + createQueryParams() { + let params = {}; + if (this.subject === 'COORDINATES') { - let params = { - group: common.trimToNull(this.coordinatesGroup), - name: common.trimToNull(this.coordinatesName), - version: common.trimToNull(this.coordinatesVersion), - }; - let esc = encodeURIComponent; - return Object.keys(params) - .filter((k) => params[k]) - .map((k) => esc(k) + '=' + esc(params[k])) - .join('&'); + if (this.coordinatesGroup) + params.group = common.trimToNull(this.coordinatesGroup); + if (this.coordinatesName) + params.name = common.trimToNull(this.coordinatesName); + if (this.coordinatesVersion) + params.version = common.trimToNull(this.coordinatesVersion); } else if (this.subject === 'PACKAGE_URL') { let v = common.trimToNull(this.value); - return v != null ? 'purl=' + encodeURIComponent(v) : ''; + if (v) params.purl = v; } else if (this.subject === 'CPE') { let v = common.trimToNull(this.value); - return v != null ? 'cpe=' + encodeURIComponent(v) : ''; + if (v) params.cpe = v; } else if (this.subject === 'SWID_TAGID') { let v = common.trimToNull(this.value); - return v != null ? 'swidTagId=' + encodeURIComponent(v) : ''; + if (v) params.swid_tag_id = v; + } else if (this.subject === 'HASH') { + let v = common.trimToNull(this.value); + if (v) { + params.hash = v; + if (this.hashType) { + params.hash_type = this.hashType; + } + } } + + return params; }, performSearch: function () { - if (this.subject === 'HASH') { - let hash = encodeURIComponent(common.trimToNull(this.value)); - this.options.url = `${this.$api.BASE_URL}/${this.$api.URL_COMPONENT}/hash/${hash}`; - this.$refs.table.refresh({ silent: true }); - } else { - let queryParams = this.createQueryParams(); - this.options.url = `${this.$api.BASE_URL}/${this.$api.URL_COMPONENT}/identity?${queryParams}`; - this.$refs.table.refresh({ silent: true }); + if (this.isSearchDisabled) { + return; } - if (this.changeSearchUrl) { - if (this.subject === 'COORDINATES') { - let urlCoordinatesGroup = this.coordinatesGroup - ? encodeURIComponent(this.coordinatesGroup) - : ''; - let urlCoordinatesName = this.coordinatesName - ? encodeURIComponent(this.coordinatesName) - : ''; - let urlCoordinatesVersion = this.coordinatesVersion - ? encodeURIComponent(this.coordinatesVersion) - : ''; - this.$router.replace({ - path: 'components', - hash: - '#/search/' + - this.subject + - '/group=' + - urlCoordinatesGroup + - '/name=' + - urlCoordinatesName + - '/version=' + - urlCoordinatesVersion, - }); - } else { - let urlValue = this.value ? encodeURIComponent(this.value) : ''; - this.$router.replace({ - path: 'components', - hash: '#/search/' + this.subject + '/' + urlValue, - }); - } + this.appliedFilters = this.createQueryParams(); + }, + }, + computed: { + isSearchDisabled() { + if (this.subject === 'COORDINATES') { + return !( + this.coordinatesGroup || + this.coordinatesName || + this.coordinatesVersion + ); + } + + if (this.subject === 'HASH') { + return !(this.value && this.hashType); } + + return !this.value; }, - onPreBody: function () { - loadUserPreferencesForBootstrapTable( - this, - 'ComponentSearch', - this.$refs.table.columns, - ); - if (!this.changeSearchUrl) { - this.performSearch(); - this.changeSearchUrl = true; + tableDataBaseUrl() { + if ( + !this.appliedFilters || + Object.keys(this.appliedFilters).length === 0 + ) { + return null; } + const url = `${this.$api.BASE_URL}/api/v2/components`; + const queryParams = { ...this.appliedFilters }; + const sortBy = this.sortBy || 'name'; + const sortDirection = this.sortDirection || 'asc'; + queryParams.sort_by = sortBy; + queryParams.sort_direction = sortDirection.toUpperCase(); + return common.setQueryParams(url, queryParams); }, }, data() { @@ -207,6 +237,24 @@ export default { coordinatesGroup: null, coordinatesName: null, coordinatesVersion: null, + sortBy: null, + sortDirection: null, + appliedFilters: null, + hashType: null, + hashTypes: [ + { value: 'MD5', text: this.$t('hashes.md5') }, + { value: 'SHA1', text: this.$t('hashes.sha_1') }, + { value: 'SHA_256', text: this.$t('hashes.sha_256') }, + { value: 'SHA_384', text: this.$t('hashes.sha_384') }, + { value: 'SHA_512', text: this.$t('hashes.sha_512') }, + { value: 'SHA3_256', text: this.$t('hashes.sha3_256') }, + { value: 'SHA3_384', text: this.$t('hashes.sha3_384') }, + { value: 'SHA3_512', text: this.$t('hashes.sha3_512') }, + { value: 'BLAKE2b_256', text: this.$t('hashes.blake_256') }, + { value: 'BLAKE2b_384', text: this.$t('hashes.blake_384') }, + { value: 'BLAKE2b_512', text: this.$t('hashes.blake_512') }, + { value: 'BLAKE3', text: this.$t('hashes.blake3') }, + ], subjects: [ { value: 'COORDINATES', text: this.$t('message.coordinates') }, { value: 'PACKAGE_URL', text: this.$t('message.package_url') }, @@ -228,10 +276,10 @@ export default { '/dependencyGraph/' + row.uuid, ); - return row.project.directDependencies - ? ` ` + - `${xssFilters.inHTMLData(value)}` - : `${xssFilters.inHTMLData(value)}`; + return ( + ` ` + + `${xssFilters.inHTMLData(value)}` + ); }, }, { @@ -261,7 +309,7 @@ export default { }, { title: this.$t('message.internal'), - field: 'isInternal', + field: 'internal', sortable: false, align: 'center', class: 'tight', @@ -279,7 +327,7 @@ export default { }, { title: this.$t('message.swid_tagid'), - field: 'swidTagId', + field: 'swid_tag_id', sortable: true, formatter(value, row, index) { return xssFilters.inHTMLData(common.valueWithDefault(value, '')); @@ -303,24 +351,24 @@ export default { }, { title: this.$t('message.license_name'), - field: 'resolvedLicense.licenseId', - sortable: true, + field: 'resolved_license.license_id', + sortable: false, visible: false, - formatter(resolvedLicense, row, index) { - if (typeof resolvedLicense === 'undefined') { + formatter(resolved_license, row, index) { + if (typeof resolved_license === 'undefined') { return '-'; // No resolvedLicense info available } let url = xssFilters.uriInUnQuotedAttr( '../licenses/' + - encodeURIComponent(row.resolvedLicense.licenseId), + encodeURIComponent(row.resolved_license.license_id), ); - return `${xssFilters.inHTMLData(row.resolvedLicense.name)}`; + return `${xssFilters.inHTMLData(row.resolved_license.name)}`; }, }, { title: this.$t('message.risk_score'), - field: 'lastInheritedRiskScore', + field: 'last_inherited_risk_score', sortable: true, visible: false, class: 'tight', @@ -353,60 +401,20 @@ export default { }.bind(this), }, ], - data: [], - options: { - onPostBody: this.initializeTooltips, - search: false, + tableOptions: { showColumns: true, showRefresh: true, - pagination: true, silentSort: false, toolbar: '#componentSearchToolbar', - sidePagination: 'server', - queryParamsType: 'pageSize', - pageList: '[10, 25, 50, 100]', - pageSize: - localStorage && - localStorage.getItem('ComponentSearchPageSize') !== null - ? Number(localStorage.getItem('ComponentSearchPageSize')) - : 10, - sortName: - localStorage && - localStorage.getItem('ComponentSearchSortName') !== null - ? localStorage.getItem('ComponentSearchSortName') - : undefined, - sortOrder: - localStorage && - localStorage.getItem('ComponentSearchSortOrder') !== null - ? localStorage.getItem('ComponentSearchSortOrder') - : undefined, icons: { refresh: 'fa-refresh', }, - //toolbar: '#componentSearchToolbar', - responseHandler: function (res, xhr) { - res.total = xhr.getResponseHeader('X-Total-Count'); - return res; - }, - url: `${this.$api.BASE_URL}/${this.$api.URL_COMPONENT}/identity`, - onPageChange: (number, size) => { - if (localStorage) { - localStorage.setItem('ComponentSearchPageSize', size.toString()); - } - }, - onColumnSwitch: (field, checked) => { - if (localStorage) { - localStorage.setItem( - 'ComponentSearchShow' + common.capitalize(field), - checked.toString(), - ); - } - }, + sortName: 'name', + sortOrder: 'asc', + customSort: () => {}, onSort: (name, order) => { - if (localStorage) { - localStorage.setItem('ComponentSearchSortName', name); - localStorage.setItem('ComponentSearchSortOrder', order); - } + this.sortBy = name; + this.sortDirection = order; }, }, };