File: //proc/self/root/proc/self/root/proc/self/cwd/nueva/modules/wnetsecurity/views/js/admin/config.js
/**
* Copyright since 2014 Waynet Sp. z o.o.
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@waynet.pl so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop-project.org/ for more information.
*
* @author Waynet Sp. z o.o. <kontakt@waynet.pl>
* @copyright since 2014 Waynet Sp. z o.o.
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
document.addEventListener("DOMContentLoaded", () => {
window?.psaccountsVue?.init();
if (!window?.psaccountsVue?.isOnboardingCompleted()) {
return;
}
const cdc = window.cloudSyncSharingConsent;
cdc.init('#prestashop-cloudsync');
class VulnerabilityReportsList {
initialized = false;
templates = {};
selectors = {
container: '.js-vulnerability-reports-container',
info: '.js-vulnerability-reports-info',
templates: {
report: '.js-vulnerability-report-template',
item: '.js-vulnerability-report-item-template',
loadMore: '.js-load-vulnerability-reports-template',
},
report: {
container: '.js-report-container',
date: '.js-report-date',
button: '.js-report-collapse-toggle',
itemsWrapper: '.js-vulnerability-report-items-wrapper',
items: '.js-vulnerability-report-items',
showHidden: '.js-show-hidden-report-items',
},
item: {
container: '.js-report-item-container',
identifier: '.js-item-identifier',
type: '.js-item-type',
severity: '.js-item-severity',
description: '.js-item-description',
contactLink: '.js-item-contact-link',
toggleHidden: '.js-item-toggle-hidden-button',
},
loadMore: '.js-load-vulnerability-reports',
}
classes = {
hideItems: 'vulnerability-report-hide-items',
}
constructor(wrapper, config) {
this.wrapper = wrapper;
this.config = config;
this.nextPage = 1;
this.container = wrapper.querySelector(this.selectors.container);
this.info = wrapper.querySelector(this.selectors.info);
for (const [key, selector] of Object.entries(this.selectors.templates)) {
this.templates[key] = wrapper.querySelector(selector);
}
}
init() {
if (this.initialized) {
return;
}
if (!this.config.hasValidSubscription) {
this.info.textContent = this.config.translations.status.subscribe;
return;
}
this.initReports().then((report) => {
if (null !== report) {
this.initEvents();
this.initialized = true;
} else {
setTimeout(this.init, 1.2e6)
}
});
}
initReports() {
return this.getLastReport()
.then((report) => {
if (null !== report) {
this.container.appendChild(this.createReportNode(report));
const loadMoreWrapper = this.templates.loadMore.content.cloneNode(true);
this.loadMoreButton = loadMoreWrapper.querySelector(this.selectors.loadMore);
this.container.appendChild(loadMoreWrapper);
this.info.textContent = '';
} else {
this.info.textContent = this.config.translations.status.firstReport;
}
return report;
})
.catch(error => this.handleRequestError(error));
}
initEvents() {
const itemToggleHiddenClass = this.selectors.item.toggleHidden.substring(1);
const reportShowHiddenClass = this.selectors.report.showHidden.substring(1);
this.loadMoreButton.addEventListener('click', (e) => this.handleLoadMore(e));
this.wrapper.addEventListener('click', (e) => {
if (e.target.classList.contains(itemToggleHiddenClass)) {
this.handleToggleHiddenItem(e);
} else if (e.target.classList.contains(reportShowHiddenClass)) {
this.handleShowHidden(e);
}
});
}
handleToggleHiddenItem(e) {
e.preventDefault();
const toggleHidden = e.target;
const container = toggleHidden.closest(this.selectors.item.container);
const hidden = 'false' === container.dataset.hidden;
const uri = container.dataset.uri;
this.updateItem(uri, hidden)
.then(() => {
this.wrapper
.querySelectorAll(`${this.selectors.item.container}[data-uri="${uri}"]`)
.forEach((container) => {
container.dataset.hidden = hidden;
container.querySelector(this.selectors.item.toggleHidden).textContent = hidden
? this.config.translations.item.show
: this.config.translations.item.hide;
const reportContainer = container.closest(this.selectors.report.container);
const showHidden = reportContainer.querySelector(this.selectors.report.showHidden);
const count = hidden ? parseInt(showHidden.dataset.count) + 1 : parseInt(showHidden.dataset.count) - 1;
showHidden.dataset.count = count.toString();
showHidden.textContent = showHidden.dataset.text.replace('{count}', count);
if (0 === count) {
showHidden.style.display = 'none';
} else if (reportContainer.classList.contains(this.classes.hideItems)) {
showHidden.style.removeProperty('display');
}
});
})
.catch(error => this.handleRequestError(error));
}
handleShowHidden(e) {
e.preventDefault();
e.stopPropagation();
const showHidden = e.target;
const container = showHidden.closest(this.selectors.report.container);
container.classList.remove(this.classes.hideItems);
showHidden.style.display = 'none';
}
handleLoadMore(e) {
e.preventDefault();
this.getReports(this.nextPage)
.then((data) => {
for (const report of data.reports) {
if (null !== this.wrapper.querySelector(`${this.selectors.report.container}[data-id="${report.id}"]`)) {
continue;
}
this.container.insertBefore(this.createReportNode(report), this.loadMoreButton.parentNode);
}
if (null !== data.nextPageUri) {
this.nextPage += 1;
} else {
this.loadMoreButton.remove();
this.loadMoreButton = null;
}
})
.catch(error => this.handleRequestError(error));
}
async getLastReport() {
return this.sendRequest(this.config.urls.lastReport).then((response) => {
switch (response.status) {
case 200:
return response.json();
case 404:
return null;
default:
throw response;
}
});
}
async getReports(page = 1) {
const url = new URL(this.config.urls.reports);
url.searchParams.set('page', page.toString());
return this.sendRequest(url).then((response) => {
if (200 === response.status) {
return response.json();
}
throw response;
});
}
async updateItem(uri, hidden) {
const payload = {
uri,
hidden,
}
return this.sendRequest(this.config.urls.updateVulnerability, {
method: 'PATCH',
body: JSON.stringify(payload),
headers: {
'content-type': 'application/json'
},
})
.then((response) => {
if (204 === response.status) {
return;
}
throw response;
});
}
createReportNode(report) {
const wrapperId = `report_${report.id}`;
const node = this.templates.report.content.cloneNode(true);
node.querySelector(this.selectors.report.container).dataset.id = report.id;
node.querySelector(this.selectors.report.date).textContent = report.createdAt;
node.querySelector(this.selectors.report.button).dataset.target = `#${wrapperId}`;
node.querySelector(this.selectors.report.itemsWrapper).id = wrapperId;
let hiddenCount = 0;
const itemsContainer = node.querySelector(this.selectors.report.items);
for (const vulnerability of report.items) {
itemsContainer.appendChild(this.createItemNode(vulnerability));
if (vulnerability.hidden) {
++hiddenCount;
}
}
const showHidden = node.querySelector(this.selectors.report.showHidden);
showHidden.dataset.count = hiddenCount;
if (0 === hiddenCount) {
showHidden.style.display = 'none';
} else {
showHidden.textContent = showHidden.dataset.text.replace('{count}', hiddenCount);
}
return node;
}
createItemNode(vulnerability) {
const node = this.templates.item.content.cloneNode(true);
const container = node.querySelector(this.selectors.item.container);
container.classList.add(this.getItemContainerClass(vulnerability.severity));
container.dataset.uri = vulnerability.uri;
container.dataset.hidden = vulnerability.hidden;
const link = node.querySelector(this.selectors.item.identifier);
link.href = vulnerability.source;
link.textContent = vulnerability.identifier;
node.querySelector(this.selectors.item.severity).textContent = this.translateSeverity(vulnerability.severity);
node.querySelector(this.selectors.item.type).textContent = this.translateType(vulnerability.type);
node.querySelector(this.selectors.item.description).textContent = vulnerability.description;
node.querySelector(this.selectors.item.toggleHidden).textContent = vulnerability.hidden
? this.config.translations.item.show
: this.config.translations.item.hide;
const contactLink = node.querySelector(this.selectors.item.contactLink);
const url = new URL(contactLink.href);
const subject = contactLink.dataset.subject.replace('{vulnerability_id}', vulnerability.identifier);
url.searchParams.set('subject', subject);
url.search = url.search.replaceAll('+', '%20');
contactLink.href = url.toString();
return node;
}
async sendRequest(url, config = {}) {
config.headers ??= {};
config.headers.accept = 'application/json';
return fetch(url, config);
}
translateType(value) {
return this.config.translations.vulnerability.type[value] ?? value;
}
translateSeverity(value) {
return this.config.translations.vulnerability.severity[value] ?? value;
}
getItemContainerClass(severity) {
switch (severity) {
case 'CRITICAL':
return 'bg-dark';
case 'HIGH':
return 'bg-danger';
case 'MEDIUM':
return 'bg-warning';
default:
return 'bg-info';
}
}
handleRequestError(error) {
if (error instanceof Response) {
this.handleResponseError(error);
}
console.log(error);
}
handleResponseError(response) {
response.json().then((data) => {
if ('error' in data) {
showErrorMessage(data.error);
}
console.log(data);
});
}
}
const wrapper = document.getElementById('vulnerability-reports-wrapper');
wrapper.style.removeProperty('display');
const reportList = new VulnerabilityReportsList(wrapper, window.wnetSecurityConfig);
reportList.init();
window.psBilling.initialize(window.psBillingContext.context, '#ps-billing', '#ps-modal', (type) => {
switch (type) {
case window.psBilling.EVENT_HOOK_TYPE.SUBSCRIPTION_CREATED:
case window.psBilling.EVENT_HOOK_TYPE.SUBSCRIPTION_UPDATED:
case window.psBilling.EVENT_HOOK_TYPE.SUBSCRIPTION_REACTIVATED:
window.wnetSecurityConfig.hasValidSubscription = true;
reportList.init();
break;
default:
break;
}
});
});