Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordiosmosis <diosmosis@users.noreply.github.com>2018-10-03 08:59:54 +0300
committerGitHub <noreply@github.com>2018-10-03 08:59:54 +0300
commit67eaa2c0381933d5e38180a2159044893447acca (patch)
tree6810978ef7295aeeaeb2256b95712111cea07c96 /plugins/Overlay
parentae872e501015ec5ed5a538c23f6e090ce3089c66 (diff)
Use postMessage instead of directly making API calls in the overlay iframe. (#13446)
* Use postMessage instead of directly making API calls in the overlay iframe. * Make sure it will work when Matomo is on a subfolder. * Increase overlay security with domain and method whitelists. * Try to fix UI test. * Fix tests + UI test blacklist check. * broadcast.getValuesFromUrl does not decode URL params.
Diffstat (limited to 'plugins/Overlay')
-rw-r--r--plugins/Overlay/Controller.php2
-rw-r--r--plugins/Overlay/client/client.js70
-rw-r--r--plugins/Overlay/config/ui-test.php2
-rw-r--r--plugins/Overlay/javascripts/Piwik_Overlay.js83
-rw-r--r--plugins/Overlay/templates/index.twig2
5 files changed, 145 insertions, 14 deletions
diff --git a/plugins/Overlay/Controller.php b/plugins/Overlay/Controller.php
index 8b8b5b6df7..c16d8923a7 100644
--- a/plugins/Overlay/Controller.php
+++ b/plugins/Overlay/Controller.php
@@ -23,6 +23,7 @@ use Piwik\Segment;
use Piwik\Tracker\Action;
use Piwik\Tracker\PageUrl;
use Piwik\View;
+use Piwik\Plugins\SitesManager;
class Controller extends \Piwik\Plugin\Controller
{
@@ -53,6 +54,7 @@ class Controller extends \Piwik\Plugin\Controller
$view->segment = Request::getRawSegmentFromRequest();
$view->ssl = ProxyHttp::isHttps();
+ $view->siteUrls = SitesManager\API::getInstance()->getSiteUrlsFromId($this->site->getId());
$this->outputCORSHeaders();
return $view->render();
diff --git a/plugins/Overlay/client/client.js b/plugins/Overlay/client/client.js
index 9ae78cf3b1..0bd74c371e 100644
--- a/plugins/Overlay/client/client.js
+++ b/plugins/Overlay/client/client.js
@@ -1,11 +1,16 @@
var Piwik_Overlay_Client = (function () {
+ var DOMAIN_PARSE_REGEX = /^http(s)?:\/\/(www\.)?([^\/]*)/i;
+
/** jQuery */
var $;
/** Url of the Piwik root */
var piwikRoot;
+ /** protocol and domain of Piwik root */
+ var piwikOrigin;
+
/** Piwik idsite */
var idSite;
@@ -15,12 +20,18 @@ var Piwik_Overlay_Client = (function () {
/** Reference to the status bar DOM element */
var statusBar;
+ /** Counter for request IDs for postMessage based API requests. */
+ var lastRequestId = 0;
+
+ /** Map of callbacks for postMessage based API requests. */
+ var requestCallbacks = {};
+
/** Load the client CSS */
function loadCss() {
var css = c('link').attr({
rel: 'stylesheet',
type: 'text/css',
- href: piwikRoot + 'plugins/Overlay/client/client.css'
+ href: piwikRoot + '/plugins/Overlay/client/client.css'
});
$('head').append(css);
}
@@ -51,7 +62,7 @@ var Piwik_Overlay_Client = (function () {
// check whether the session has been opened in a new tab (instead of an iframe)
if (window != window.top) {
var iframe = c('iframe', false, {
- src: piwikRoot + 'index.php?module=Overlay&action=notifyParentIframe#' + window.location.href
+ src: piwikRoot + '/index.php?module=Overlay&action=notifyParentIframe#' + window.location.href
}).css({width: 0, height: 0, border: 0});
$('body').append(iframe);
@@ -81,11 +92,48 @@ var Piwik_Overlay_Client = (function () {
return el;
}
+ function nextRequestId() {
+ var nextId = lastRequestId + 1;
+ lastRequestId = nextId;
+ return nextId;
+ }
+
+ function handlePostMessages() {
+ window.addEventListener("message", function (event) {
+ if (event.origin !== piwikOrigin) {
+ return;
+ }
+
+ var strData = event.data.split(':', 3);
+ if (strData[0] !== 'overlay.response') {
+ return;
+ }
+
+ var requestId = strData[1];
+ if (!requestCallbacks[requestId]) {
+ return;
+ }
+
+ var callback = requestCallbacks[requestId];
+ delete requestCallbacks[requestId];
+
+ var data = JSON.parse(decodeURIComponent(strData[2]));
+ if (typeof data.result !== 'undefined'
+ && data.result === 'error'
+ ) {
+ alert('Error: ' + data.message);
+ } else {
+ callback(data);
+ }
+ }, false);
+ }
+
return {
/** Initialize in-site analytics */
initialize: function (pPiwikRoot, pIdSite, pPeriod, pDate, pSegment) {
piwikRoot = pPiwikRoot;
+ piwikOrigin = piwikRoot.match(DOMAIN_PARSE_REGEX)[0];
idSite = pIdSite;
period = pPeriod;
date = pDate;
@@ -95,6 +143,7 @@ var Piwik_Overlay_Client = (function () {
var loading = this.loadingNotification;
loadJQuery(function () {
+ handlePostMessages();
notifyPiwikOfLocation();
loadCss();
@@ -138,13 +187,13 @@ var Piwik_Overlay_Client = (function () {
};
script.onload = onLoad;
- script.src = piwikRoot + relativePath + '?v=1';
+ script.src = piwikRoot + '/' + relativePath + '?v=1';
head.appendChild(script);
},
/** Piwik Overlay API Request */
api: function (method, callback, additionalParams) {
- var url = piwikRoot + 'index.php?module=API&method=Overlay.' + method
+ var url = piwikRoot + '/index.php?module=API&method=Overlay.' + method
+ '&idSite=' + idSite + '&period=' + period + '&date=' + date + '&format=JSON&filter_limit=-1';
if (segment) {
@@ -155,14 +204,11 @@ var Piwik_Overlay_Client = (function () {
url += '&' + additionalParams;
}
- $.getJSON(url + "&jsoncallback=?", function (data) {
- if (typeof data.result != 'undefined' && data.result == 'error') {
- alert('Error: ' + data.message);
- }
- else {
- callback(data);
- }
- });
+ var requestId = nextRequestId();
+ requestCallbacks[requestId] = callback;
+
+ var matomoFrame = window.parent;
+ matomoFrame.postMessage('overlay.call:' + requestId + ':' + encodeURIComponent(url), piwikOrigin);
},
/**
diff --git a/plugins/Overlay/config/ui-test.php b/plugins/Overlay/config/ui-test.php
index 1bb5ae8b75..2951f8e48f 100644
--- a/plugins/Overlay/config/ui-test.php
+++ b/plugins/Overlay/config/ui-test.php
@@ -9,6 +9,8 @@ return array(
)),
'tests.ui.url_normalizer_blacklist.controller' => DI\add(array(
'Overlay.renderSidebar',
+ 'Overlay.index',
+ 'Overlay.startOverlaySession',
)),
); \ No newline at end of file
diff --git a/plugins/Overlay/javascripts/Piwik_Overlay.js b/plugins/Overlay/javascripts/Piwik_Overlay.js
index afcbc268ad..4c06f75cd0 100644
--- a/plugins/Overlay/javascripts/Piwik_Overlay.js
+++ b/plugins/Overlay/javascripts/Piwik_Overlay.js
@@ -7,6 +7,14 @@
var Piwik_Overlay = (function () {
+ var DOMAIN_PARSE_REGEX = /^http(s)?:\/\/(www\.)?([^\/]*)/i;
+ var ORIGIN_PARSE_REGEX = /^https?:\/\/[^\/]*/;
+ var ALLOWED_API_REQUEST_WHITELIST = [
+ 'Overlay.getTranslations',
+ 'Overlay.getExcludedQueryParameters',
+ 'Overlay.getFollowingPages',
+ ];
+
var $body, $iframe, $sidebar, $main, $location, $loading, $errorNotLoading;
var $rowEvolutionLink, $transitionsLink, $visitorLogLink;
@@ -18,6 +26,7 @@ var Piwik_Overlay = (function () {
var iframeCurrentPageNormalized = '';
var iframeCurrentActionLabel = '';
var updateComesFromInsideFrame = false;
+ var iframeOrigin = '';
/** Load the sidebar for a url */
function loadSidebar(currentUrl) {
@@ -26,7 +35,7 @@ var Piwik_Overlay = (function () {
$location.html('&nbsp;').unbind('mouseenter').unbind('mouseleave');
iframeCurrentPage = currentUrl;
- iframeDomain = currentUrl.match(/http(s)?:\/\/(www\.)?([^\/]*)/i)[3];
+ iframeDomain = currentUrl.match(DOMAIN_PARSE_REGEX)[3];
var params = {
module: 'Overlay',
@@ -135,11 +144,31 @@ var Piwik_Overlay = (function () {
return location;
}
+ function setIframeOrigin(location) {
+ iframeOrigin = location.match(ORIGIN_PARSE_REGEX)[0];
+
+ // unset iframe origin if it is not one of the site URLs
+ var validSiteOrigins = Piwik_Overlay.siteUrls.map(function (url) {
+ return url.match(ORIGIN_PARSE_REGEX)[0];
+ });
+
+ if (iframeOrigin && validSiteOrigins.indexOf(iframeOrigin) === -1) {
+ try {
+ console.log('Found invalid iframe origin in hash URL: ' + iframeOrigin);
+ } catch (e) {
+ // ignore
+ }
+ iframeOrigin = null;
+ }
+ }
+
/** $.history callback for hash change */
function hashChangeCallback(urlHash) {
var location = getOverlayLocationFromHash(urlHash);
location = Overlay_Helper.decodeFrameUrl(location);
+ setIframeOrigin(location);
+
if (location == iframeCurrentPageNormalized) {
return;
}
@@ -158,6 +187,54 @@ var Piwik_Overlay = (function () {
updateComesFromInsideFrame = false;
}
+ function handleApiRequests() {
+ window.addEventListener("message", function (event) {
+ if (event.origin !== iframeOrigin || !iframeOrigin) {
+ return;
+ }
+
+ var strData = event.data.split(':', 3);
+ if (strData[0] !== 'overlay.call') {
+ return;
+ }
+
+ var requestId = strData[1];
+ var url = decodeURIComponent(strData[2]);
+
+ var params = broadcast.getValuesFromUrl(url);
+ Object.keys(params).forEach(function (name) {
+ params[name] = decodeURIComponent(params[name]);
+ });
+ params.module = 'API';
+ params.action = 'index';
+
+ if (ALLOWED_API_REQUEST_WHITELIST.indexOf(params.method) === -1) {
+ sendResponse({
+ result: 'error',
+ message: "'" + params.method + "' method is not allowed.",
+ });
+ return;
+ }
+
+ angular.element(document).injector().invoke(['piwikApi', function (piwikApi) {
+ piwikApi.fetch(params)
+ .then(function (response) {
+ sendResponse(response);
+ }).catch(function (err) {
+ sendResponse({
+ result: 'error',
+ message: err.message,
+ });
+ });
+ }]);
+
+ function sendResponse(data) {
+ var message = 'overlay.response:' + requestId + ':' + encodeURIComponent(JSON.stringify(data));
+ $iframe[0].contentWindow.postMessage(message, iframeOrigin);
+ }
+ }, false);
+ }
+
return {
/** This method is called when Overlay loads */
@@ -181,7 +258,6 @@ var Piwik_Overlay = (function () {
$visitorLogLink = $('#overlaySegmentedVisitorLog');
adjustDimensions();
-
showLoading();
// apply initial dimensions
@@ -206,6 +282,8 @@ var Piwik_Overlay = (function () {
hashChangeCallback('');
}
+ handleApiRequests();
+
// handle date selection
var $select = $('select#overlayDateRangeSelect').change(function () {
var parts = $(this).val().split(';');
@@ -286,6 +364,7 @@ var Piwik_Overlay = (function () {
window.location.replace(newLocation);
} else {
// happens when the url is changed by hand or when the l parameter is there on page load
+ setIframeOrigin(currentUrl);
loadSidebar(currentUrl);
}
}
diff --git a/plugins/Overlay/templates/index.twig b/plugins/Overlay/templates/index.twig
index 97ed8783ff..60c64e0081 100644
--- a/plugins/Overlay/templates/index.twig
+++ b/plugins/Overlay/templates/index.twig
@@ -65,6 +65,8 @@
<script type="text/javascript">
broadcast._isInit = true;
$(function () {
+ Piwik_Overlay.siteUrls = {{ siteUrls|json_encode|raw }};
+
var iframeSrc = 'index.php?module=Overlay&action=startOverlaySession&idSite={{ idSite }}&period={{ period }}&date={{ rawDate }}&segment={{ segment }}';
Piwik_Overlay.init(iframeSrc, '{{ idSite }}', '{{ period }}', '{{ rawDate }}', '{{ segment }}');