diff --git a/js/org/gigapan/timelapse/crossdomain_api.js b/js/org/gigapan/timelapse/crossdomain_api.js index ead98565..4ce9f9db 100644 --- a/js/org/gigapan/timelapse/crossdomain_api.js +++ b/js/org/gigapan/timelapse/crossdomain_api.js @@ -63,38 +63,50 @@ function setupPostMessageHandlers() { }); // Handles the cross-domain iframe request to seek a time machine to the specified time. - pm.bind("timemachine-seek", function(data) { - if (timelapse) - timelapse.seek(data); + pm.bind("timemachine-seek", function(unsafe_data) { + if (unsafe_data && typeof(unsafe_data) !== 'undefined' && timelapse) + timelapse.seek(unsafe_data); }); // Handles the cross-domain iframe request to change the view of a time machine. - pm.bind("timemachine-set-view", function(data) { - if (timelapse) { - timelapse.setNewView(data.view, data.doWarp, data.doPlay); + pm.bind("timemachine-set-view", function(unsafe_data) { + if (unsafe_data && typeof(unsafe_data) !== 'undefined' && timelapse) { + // Sanitize data + var safe_data = {}; + safe_data.view = timelapse.unsafeViewToView(unsafe_data.view); + safe_data.doWarp = !!unsafe_data.doWarp; + safe_data.doPlay = !!unsafe_data.doPlay; + timelapse.setNewView(safe_data.view, safe_data.doWarp, safe_data.doPlay); } }); - // Handles the cross-domain iframe request of changing the view of a time machine based - // on a share URL. - pm.bind("timemachine-set-share-view", function(data) { - if (timelapse) { - var viewArray = data.v.split(","); - var view; - var doWarp = true; - if (viewArray) - view = timelapse.unsafeViewToView(viewArray); - if (view) - timelapse.setNewView(view, doWarp); - var time = data.t; - if (time) - timelapse.seek(time); + // Handles the cross-domain iframe request of changing the view of a time machine based on a share URL. + pm.bind("timemachine-set-share-view", function(unsafe_data) { + if (unsafe_data && typeof(unsafe_data) !== 'undefined' && timelapse) { + // If a share URL (e.g. #v=44.96185,59.06233,4.5,latLng&t=0.10) is passed in + // as a string, then unpack it based on the hash vars. + // Otherwise we are dealing with an object of unpacked hash vars, so move on. + if (typeof(unsafe_data) === "string") { + if (unsafe_data.substr(0,1) == "#") + unsafe_data = unsafe_data.slice(1); + unsafe_data = org.gigapan.Util.unpackVars(unsafe_data); + } + + if (unsafe_data.v) { + var newView = timelapse.unsafeViewToView(unsafe_data.v.split(",")); + // Always warp to the new view (i.e. pass in true for the second value) + timelapse.setNewView(newView, true); + } + if (unsafe_data.t) { + var newTime = parseFloat(unsafe_data.t); + timelapse.seek(newTime); + } } }); // Handles the cross-domain iframe request of going to a location on the presentation slider - pm.bind("timemachine-goto-presentation-slide", function(slideTitle) { - var slideId = slideTitle.split(' ').join('_'); + pm.bind("timemachine-goto-presentation-slide", function(unsafe_slideTitle) { + var slideId = unsafe_slideTitle.split(' ').join('_'); var $slideContainer = $("#" + slideId).parent(); var keyframeId = $slideContainer.attr("id").split("_")[3]; timelapse.getPresentationSlider().getPresentationSliderViewer().selectAndGo($slideContainer, keyframeId, undefined, undefined, true); diff --git a/js/org/gigapan/timelapse/snaplapseViewer.js b/js/org/gigapan/timelapse/snaplapseViewer.js index 74820243..37686b4a 100644 --- a/js/org/gigapan/timelapse/snaplapseViewer.js +++ b/js/org/gigapan/timelapse/snaplapseViewer.js @@ -1254,12 +1254,12 @@ function playCachedSnaplapse(snaplapseId) { snaplapse.resetKeyframe(); if (usePresentationSlider) { $("#" + composerDivId + " .snaplapse_keyframe_container").scrollLeft(0); - var unsafeHashVars = UTIL.getUnsafeHashVars(); + var unsafeHashObj = UTIL.getUnsafeHashVars(); // Go to the desired keyframe if there is no shared view and no tour - if ( typeof unsafeHashVars.v == "undefined" && typeof unsafeHashVars.tour == "undefined") { + if ( typeof unsafeHashObj.v == "undefined" && typeof unsafeHashObj.tour == "undefined") { var $desiredSlide; - if ( typeof unsafeHashVars.slide != "undefined") - $desiredSlide = $("#" + unsafeHashVars.slide); + if ( typeof unsafeHashObj.slide != "undefined") + $desiredSlide = $("#" + unsafeHashObj.slide); if ($desiredSlide && $desiredSlide.length > 0) $desiredSlide[0].click(); else { diff --git a/js/org/gigapan/timelapse/timelapse.js b/js/org/gigapan/timelapse/timelapse.js index 82dedc2d..b77e2853 100644 --- a/js/org/gigapan/timelapse/timelapse.js +++ b/js/org/gigapan/timelapse/timelapse.js @@ -991,6 +991,42 @@ if (!window['$']) { // Extract a safe view object from an unsafe view string. var unsafeViewToView = function(viewParam) { var view = null; + + if (!viewParam) + return view; + + // If the view is not a string (i.e an object) then we need to break it up into one + // so that we can sanitize it below. + if (viewParam.center || viewParam.bbox) { + var tmpViewParam = []; + if (viewParam.center) { + var isLatLng = false; + var centerView = viewParam.center; + for (var key in centerView) { + tmpViewParam.push(centerView[key]); + if (key == "lat") + isLatLng = true; + } + tmpViewParam.push(viewParam.zoom); + isLatLng ? tmpViewParam.push("latLng") : tmpViewParam.push("pts"); + viewParam = tmpViewParam; + } else if (viewParam.bbox) { + var isLatLng = false; + var bboxView = viewParam.bbox; + for (var key in bboxView) { + if (key == "ne" || key == "sw") { + isLatLng = true; + for (var innerKey in bboxView[key]) + tmpViewParam.push(bboxView[key][innerKey]); + } else { + tmpViewParam.push(bboxView[key]); + } + } + isLatLng ? tmpViewParam.push("latLng") : tmpViewParam.push("pts"); + viewParam = tmpViewParam; + } + } + if (viewParam.indexOf("latLng") != -1) { if (viewParam.length == 4) view = { @@ -1392,12 +1428,12 @@ if (!window['$']) { // Handle any hash variables related to time machines var handleHashChange = function() { - var unsafeHashVars = UTIL.getUnsafeHashVars(); - var newView = getViewFromHash(unsafeHashVars); - var newTime = getTimeFromHash(unsafeHashVars); - var tourJSON = getTourFromHash(unsafeHashVars); - var presentationJSON = getPresentationFromHash(unsafeHashVars); - var modisLock = getModisLockFromHash(unsafeHashVars); + var unsafeHashObj = UTIL.getUnsafeHashVars(); + var newView = getViewFromHash(unsafeHashObj); + var newTime = getTimeFromHash(unsafeHashObj); + var tourJSON = getTourFromHash(unsafeHashObj); + var presentationJSON = getPresentationFromHash(unsafeHashObj); + var modisLock = getModisLockFromHash(unsafeHashObj); if (newView || newTime || tourJSON || presentationJSON || modisLock) { if (newView) _setNewView(newView, true); @@ -1428,49 +1464,52 @@ if (!window['$']) { return false; }; - // Gets safe view values from an unsafe hash string. - var getViewFromHash = function(unsafeHashVars) { - if (unsafeHashVars && unsafeHashVars.v) { - var newView = unsafeViewToView(unsafeHashVars.v.split(",")); + // Gets safe view values (Object) from an unsafe object containing key-value pairs from the URL hash. + var getViewFromHash = function(unsafeHashObj) { + if (unsafeHashObj && unsafeHashObj.v) { + var newView = unsafeViewToView(unsafeHashObj.v.split(",")); return newView; } return null; }; - // Gets a safe time value from an unsafe hash string. - var getTimeFromHash = function(unsafeHashVars) { - if (unsafeHashVars && unsafeHashVars.t) { - var newTime = parseFloat(unsafeHashVars.t); + // Gets a safe time value (Float) from an unsafe object containing key-value pairs from the URL hash. + // TODO: what if time is 0? + var getTimeFromHash = function(unsafeHashObj) { + if (unsafeHashObj && unsafeHashObj.t) { + var newTime = parseFloat(unsafeHashObj.t); return newTime; } return null; }; - // Gets a safe MODIS month lock value from an unsafe hash string. - var getModisLockFromHash = function(unsafeHashVars) { - if (unsafeHashVars && unsafeHashVars.l) { - var newMonthLock = unsafeHashVars.l; + // Gets a safe MODIS month lock value (String) from an unsafe object containing key-value pairs from the URL hash. + var getModisLockFromHash = function(unsafeHashObj) { + if (unsafeHashObj && unsafeHashObj.l) { + var newMonthLock = String(unsafeHashObj.l); return newMonthLock; } return null; }; - // Gets safe tour JSON from an unsafe hash string. - var getTourFromHash = function(unsafeHashVars) { - if (unsafeHashVars && unsafeHashVars.tour) { + // Gets safe tour JSON from an unsafe object containing key-value pairs from the URL hash. + // The JSON returned is safe because calls to urlStringToJSON go to carefully-designed methods that use strict encoders (and naming conventions to mark strings not strictly sanitized) to ensure the input is safe. + var getTourFromHash = function(unsafeHashObj) { + if (unsafeHashObj && unsafeHashObj.tour) { if (snaplapse) { - var tourJSON = snaplapse.urlStringToJSON(unsafeHashVars.tour); + var tourJSON = snaplapse.urlStringToJSON(unsafeHashObj.tour); return tourJSON; } } return null; }; - // Gets safe presentation JSON from an unsafe hash string. - var getPresentationFromHash = function(unsafeHashVars) { - if (unsafeHashVars && unsafeHashVars.presentation) { + // Gets safe presentation JSON from an unsafe object containing key-value pairs from the URL hash. + // The JSON returned is safe because calls to urlStringToJSON go to carefully-designed methods that use strict encoders (and naming conventions to mark strings not strictly sanitized) to ensure the input is safe. + var getPresentationFromHash = function(unsafeHashObj) { + if (unsafeHashObj && unsafeHashObj.presentation) { if (presentationSlider) { - var presentationJSON = presentationSlider.urlStringToJSON(unsafeHashVars.presentation); + var presentationJSON = presentationSlider.urlStringToJSON(unsafeHashObj.presentation); return presentationJSON; } } diff --git a/tests/cross_domain_test.html b/tests/cross_domain_test.html new file mode 100644 index 00000000..e4eaf2e4 --- /dev/null +++ b/tests/cross_domain_test.html @@ -0,0 +1,52 @@ + + +
+ + + + + + + +