Привет, Даниэлла, я пробовал эту интеграцию с тремя разными провайдерами чата, и после добавления всех найденных ссылок в security policy script src получаю одну и ту же ошибку CSP. В данном случае речь идёт о Tidio, но то же самое произошло с LiveChat и Pure Chat. Есть какие-то идеи, что может происходить?
Content Security Policy: Настройки страницы заблокировали загрузку ресурса по адресу eval ("script-src"). Источник: (function injected(eventName, injectedIntoContentWindow)
{
let checkRequest;
/*
* Обёртка контекста фрейма
*
* В некоторых крайних случаях Chrome не запускает контентные скрипты внутри фреймов.
* Сайты начали злоупотреблять этим фактом для доступа к незащищённым API через
* contentWindow фрейма (#4586, 5207). Поэтому, пока Chrome не будет последовательно
* запускать контентные скрипты для всех фреймов, мы должны следить за тем, чтобы
* (пере)внедрять наши обёртки при доступе к contentWindow.
*/
let injectedToString = Function.prototype.toString.bind(injected);
let injectedFrames = new WeakSet();
let injectedFramesAdd = WeakSet.prototype.add.bind(injectedFrames);
let injectedFramesHas = WeakSet.prototype.has.bind(injectedFrames);
function injectIntoContentWindow(contentWindow)
{
if (contentWindow && !injectedFramesHas(contentWindow))
{
injectedFramesAdd(contentWindow);
try
{
contentWindow[eventName] = checkRequest;
contentWindow.eval(
"(" + injectedToString() + ")('" + eventName + "', true);"
);
delete contentWindow[eventName];
}
catch (e) {}
}
}
for (let element of [HTMLFrameElement, HTMLIFrameElement, HTMLObjectElement])
{
let contentDocumentDesc = Object.getOwnPropertyDescriptor(
element.prototype, "contentDocument"
);
let contentWindowDesc = Object.getOwnPropertyDescriptor(
element.prototype, "contentWindow"
);
// Похоже, что в HTMLObjectElement.prototype.contentWindow не существует
// в старых версиях Chrome, таких как 51.
if (!contentWindowDesc)
continue;
let getContentDocument = Function.prototype.call.bind(
contentDocumentDesc.get
);
let getContentWindow = Function.prototype.call.bind(
contentWindowDesc.get
);
contentWindowDesc.get = function()
{
let contentWindow = getContentWindow(this);
injectIntoContentWindow(contentWindow);
return contentWindow;
};
contentDocumentDesc.get = function()
{
injectIntoContentWindow(getContentWindow(this));
return getContentDocument(this);
};
Object.defineProperty(element.prototype, "contentWindow",
contentWindowDesc);
Object.defineProperty(element.prototype, "contentDocument",
contentDocumentDesc);
}
/*
* Обёртка RTCPeerConnection
*
* WebRTC API в Chrome пока не позволяет блокировать
* соединения WebRTC.
* См. https://bugs.chromium.org/p/chromium/issues/detail?id=707683
*/
let RealCustomEvent = window.CustomEvent;
// Если мы были внедрены во фрейм через contentWindow, то мы можем просто
// взять копию checkRequest, оставленную для нас родительским документом. В противном
// случае нам нужно настроить её сейчас, вместе с функциями обработки событий.
if (injectedIntoContentWindow)
checkRequest = window[eventName];
else
{
let addEventListener = document.addEventListener.bind(document);
let dispatchEvent = document.dispatchEvent.bind(document);
let removeEventListener = document.removeEventListener.bind(document);
checkRequest = (url, callback) =>
{
let incomingEventName = eventName + "-" + url;
function listener(event)
{
callback(event.detail);
removeEventListener(incomingEventName, listener);
}
addEventListener(incomingEventName, listener);
dispatchEvent(new RealCustomEvent(eventName, {detail: {url}}));
};
}
// Вызывается только до кода страницы, не защищено.
function copyProperties(src, dest, properties)
{
for (let name of properties)
{
if (Object.prototype.hasOwnProperty.call(src, name))
{
Object.defineProperty(dest, name,
Object.getOwnPropertyDescriptor(src, name));
}
}
}
let RealRTCPeerConnection = window.RTCPeerConnection ||
window.webkitRTCPeerConnection;
// В Firefox есть опция (media.peerconnection.enabled) для отключения WebRTC,
// в этом случае RealRTCPeerConnection не определён.
if (typeof RealRTCPeerConnection != "undefined")
{
let closeRTCPeerConnection = Function.prototype.call.bind(
RealRTCPeerConnection.prototype.close
);
let RealArray = Array;
let RealString = String;
let {create: createObject, defineProperty} = Object;
let normalizeUrl = url =>
{
if (typeof url != "undefined")
return RealString(url);
};
let safeCopyArray = (originalArray, transform) =>
{
if (originalArray == null || typeof originalArray != "object")
return originalArray;
let safeArray = RealArray(originalArray.length);
for (let i = 0; i < safeArray.length; i++)
{
defineProperty(safeArray, i, {
configurable: false, enumerable: false, writable: false,
value: transform(originalArray[i])
});
}
defineProperty(safeArray, "length", {
configurable: false, enumerable: false, writable: false,
value: safeArray.length
});
return safeArray;
};
// Было бы гораздо проще использовать метод .getConfiguration для получения
// нормализованной и безопасной конфигурации из экземпляра RTCPeerConnection.
// К сожалению, он не реализован в нестабильной версии Chrome 59.
// См. https://www.chromestatus.com/feature/5271355306016768
let protectConfiguration = configuration =>
{
if (configuration == null || typeof configuration != "object")
return configuration;
let iceServers = safeCopyArray(
configuration.iceServers,
iceServer =>
{
let {url, urls} = iceServer;
// RTCPeerConnection не перебирает псевдомассивы urls.
if (typeof urls != "undefined" && !(urls instanceof RealArray))
urls = [urls];
return createObject(iceServer, {
url: {
configurable: false, enumerable: false, writable: false,
value: normalizeUrl(url)
},
urls: {
configurable: false, enumerable: false, writable: false,
value: safeCopyArray(urls, normalizeUrl)
}
});
}
);
return createObject(configuration, {
iceServers: {
configurable: false, enumerable: false, writable: false,
value: iceServers
}
});
};
let checkUrl = (peerconnection, url) =>
{
checkRequest(url, blocked =>
{
if (blocked)
{
// Вызов .close() выбрасывает ошибку, если соединение уже закрыто.
try
{
closeRTCPeerConnection(peerconnection);
}
catch (e) {}
}
});
};
let checkConfiguration = (peerconnection, configuration) =>
{
if (configuration && configuration.iceServers)
{
for (let i = 0; i < configuration.iceServers.length; i++)
{
let iceServer = configuration.iceServers[i];
if (iceServer)
{
if (iceServer.url)
checkUrl(peerconnection, iceServer.url);
if (iceServer.urls)
{
for (let j = 0; j < iceServer.urls.length; j++)
checkUrl(peerconnection, iceServer.urls[j]);
}
}
}
}
};
// Нестабильная версия Chrome (протестирована с 59) уже реализовала
// setConfiguration, поэтому нам нужно обернуть и его, если он существует.
// https://www.chromestatus.com/feature/5596193748942848
if (RealRTCPeerConnection.prototype.setConfiguration)
{
let realSetConfiguration = Function.prototype.call.bind(
RealRTCPeerConnection.prototype.setConfiguration
);
RealRTCPeerConnection.prototype.setConfiguration = function(configuration)
{
configuration = protectConfiguration(configuration);
// Сначала вызовем настоящий метод, чтобы он проверил конфигурацию за нас.
// Кроме того, checkRequest всё равно асинхронный.
realSetConfiguration(this, configuration);
checkConfiguration(this, configuration);
};
}
let WrappedRTCPeerConnection = function(...args)
{
if (!(this instanceof WrappedRTCPeerConnection))
return RealRTCPeerConnection();
let configuration = protectConfiguration(args[0]);
// Поскольку старый конструктор webkitRTCPeerConnection принимает необязательный
// второй аргумент, нам нужно убедиться, что мы передаём его. Это необходимо
// для старых версий Chrome, таких как 51.
let constraints = undefined;
if (args.length > 1)
constraints = args[1];
let peerconnection = new RealRTCPeerConnection(configuration,
constraints);
checkConfiguration(peerconnection, configuration);
return peerconnection;
};
WrappedRTCPeerConnection.prototype = RealRTCPeerConnection.prototype;
let boundWrappedRTCPeerConnection = WrappedRTCPeerConnection.bind();
copyProperties(RealRTCPeerConnection, boundWrappedRTCPeerConnection,
["generateCertificate", "name", "prototype"]);
RealRTCPeerConnection.prototype.constructor = boundWrappedRTCPeerConnection;
if ("RTCPeerConnection" in window)
window.RTCPeerConnection = boundWrappedRTCPeerConnection;
if ("webkitRTCPeerConnection" in window)
window.webkitRTCPeerConnection = boundWrappedRTCPeerConnection;
}
})('abp-request-aic05wltexc', true);. 468b7929-46c3-4249-b516-189e58962157:27:22
Ещё одна ошибка CSP:
Content Security Policy: Настройки страницы заблокировали загрузку ресурса по адресу inline ("script-src"). Источник: try { if (typeof Navigator.prototype.sendBeacon === 'function') { Navigator.prototype.sendBeacon = function(url, data) { return true; }; } } catch (exception) { console.error(exception); }. script.js:517:22
И ещё одна (ссылка здесь уже добавлена, к сведению):
Content Security Policy: Настройки страницы заблокировали загрузку ресурса по адресу https://widget-v4.tidiochat.com//1_23_3/static/js/widget.a6a6e2b4c2401b7c523f.js ("script-src"). xgahvvrt0kwvb7p6crbxuolt4omnin1u.js:1:12450