Topic: Content Security Policy and Juicebox

I am using many embedded galleries on my web site. I'm trying to tighten up my content security policy and that presents a problem. It is recommended that 'unsafe-inline' not be used for script-src but you need it because of the <script> used for embedding. Has anyone managed to convert it into a script that can be loaded? You'd need to be able to pass in a parameter for the URL/URI.

Re: Content Security Policy and Juicebox

You should be able to move the entire JavaScript embedding code into a separate script and then just load this script after loading the 'juicebox.js' script.
I think this should work OK.
At its most basic:

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Juicebox-Pro Gallery</title>
    <script src="jbcore/juicebox.js"></script>
    <script src="script.js"></script>
</head>
<body>
    <div id="juicebox-container"></div>
</body>
</html>

'script.js':

new juicebox({
    containerId: 'juicebox-container'
});

I'm not sure what parameter you'd like to pass in the URL but you could do so with a query string, e.g.:

http://www.example.com/index.html?text=hello

You could then fetch the query string parameter from within the script using code such as:

if (window.location.search) {
    var key = 'text';
    var queryArray = {};
    var queryComponent;
    var queryString = unescape(window.location.search);
    var re = new RegExp('([^?=&]+)(?:=([^&]*))?', 'g');
    while (queryComponent = re.exec(queryString)) {
        queryArray[queryComponent[1]] = queryComponent[2];
    }
    var value = queryArray[key];
    // Do something with 'value' variable ("hello" in the example above)
}

(This may not be the most compact/optimized code for fetching a query string but it does handle multiple query string parameters.)

I'm not sure if this is exactly what you are looking for but it might point you in the right direction.

Re: Content Security Policy and Juicebox

I was hoping to avoid passing the parameter via a query string and using a data object instead. I need to pass in the part of the shareURL and baseUrl that changes depending on the page/gallery.

Re: Content Security Policy and Juicebox

If you do not want to use a query string (or a #) to pass a parameter via a URL, then I'm not exactly sure how you want to pass a parameter to the script (intended to avoid using inline JavaScript) without actually using inline JavaScript to pass the parameter.

You could perhaps set a session cookie (and grab the cookie's contents from within the script) but then you'd probably need separate scripts (to avoid using inline JavaScript) to set the cookie's functions and to set the cookie's contents (and it all seems to be overcomplicating matters somewhat).

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Juicebox-Pro Gallery</title>
    <script src="jbcore/juicebox.js"></script>
    <script src="cookie.js"></script>
    <script src="create_cookie.js"></script>
    <script src="script.js"></script>
</head>
<body>
    <div id="juicebox-container"></div>
</body>
</html>

'cookie.js':

function createCookie(name, value) {
    document.cookie = name + '=' + escape(value) + '; path=/';
}

function readCookie(name) {
    var re = new RegExp('(?:^|;)\\s?' + name + '=(.*?)(?:;|$)', 'i'), result = document.cookie.match(re), output = null;
    if (result != null) {
        output = unescape(result[1]);
    }
    return output;
}

function eraseCookie(name) {
    var d = new Date();
    document.cookie = name + '=; path=/; expires=' + d.toUTCString();
}

'create_cookie.js':

createCookie('base', '/galleries/gallery_1/');

'script.js':

var base = readCookie('base');
eraseCookie('base');

new juicebox({
    baseUrl: base,
    containerId: 'juicebox-container'
});

I guess this might not help as it still leaves us with the problem of how to get the parameter into the 'create_cookie.js' script without using inline JavaScript. It just shifts the problem around a bit (and avoids using a query string).

I do not know how (or where) your baseUrl and shareUrl parameters are being generated but if they are already being generated in another external script, then maybe you could just set the cookie directly from within this script (and it could still be read from the 'script.js' file above).

If you just want to set a global JavaScript variable for your parameter, then the problem still exists (at least in my own understanding) of how to set it without using inline JavaScript. I guess I really need to know how and where your baseUrl and shareUrl parameters are being generated so if you could please elaborate on that, then it might help me to try to formulate a solution.
Thank you.

I hope this helps (or at least gives you a little more food for thought).

Re: Content Security Policy and Juicebox

The baseUrl and shareUrl parameters are hard coded into the page but as the juicebox data hides in a different directory structure to the web pages for each gallery I was wondering if there was a way to use a single global script and then indicate to it which juicebox/web directory was being accessed through a DATA-* on the script.
At the moment the following is embedded in a page

<!--START JUICEBOX EMBED-->
<script>
  new juicebox({
    shareURL: "https://www.mrp.net/photos/travel/manila" ,
    baseUrl : '/juicebox/travel/manila/',
    containerId : 'juicebox-container',
    galleryTitlePosition: 'NONE',
    galleryWidth : '100%',
    galleryHeight : '100%',
    backgroundColor: '#FFFFFF',
    textColor: '#FFFFFF',
    enableDirectLinks: 'FALSE',
    autoPlayOnLoad: 'TRUE',
    showAutoPlayButton: 'TRUE',
    showOpenButton: 'FALSE',
    enableLooping: 'TRUE',
    shareTwitter: 'TRUE', 
    shareFacebook: 'TRUE', 
    shareGPlus: 'FALSE',
    imageTransitionType: 'CROSS_FADE'
  });
  </script>
<div id="juicebox-container"></div>
<!--END JUICEBOX EMBED-->

where "travel/manila" is the variable part if this was a global script.

If I try something like

<!--START JUICEBOX EMBED-->
<script src="/scripts/juicebox-gallery.js" id="juicebox" data-page="travel/manila">
<div id="juicebox-container"></div>
<!--END JUICEBOX EMBED-->

where juicebox-gallery.js is

var page = document.getElementById("juicebox").getAttribute("data-page");
var shareURL = 'https://www.mrp.net/photos/' + page;
var baseUrl = '/juicebox/' + page + '/';
new juicebox({
        shareURL : shareURL,
        baseUrl : baseUrl,
        containerId : 'juicebox-container'
      });

I get a lot of errors on the javascript console such as

VM3355:1 Uncaught TypeError: Cannot read property 'trySetContainerSize' of null
    at display_error_message (eval at <anonymous> (juicebox.js:14), <anonymous>:1:261537)
    at eval (eval at <anonymous> (juicebox.js:14), <anonymous>:1:263492)

Re: Content Security Policy and Juicebox

It looks like what you are doing should work.
In fact, I have just recreated your setup and it works for me, without any console errors.

The console errors you are seeing may be unconnected to the passing of the data value.
"Cannot read property 'trySetContainerSize'" certainty sounds like a problem with Juicebox being unable to size the gallery correctly.

Please post the URL to your gallery's web page so that I can see the problem for myself.
Once I'm able to see the problem live on your web server, I might be able to determine the exact cause of the problem and propose a solution.
Thank you.

Also, if you are not already using the latest version of Juicebox-Pro (v1.5.1), then please try upgrading your gallery to see if this helps.
(I have been using Juicebox-Pro v1.5.1 in my own tests and have not seen the console errors you reported.)
If necessary, full instructions for downloading the latest version of Juicebox-Pro and upgrading existing galleries can be found in the Upgrading Juicebox support section.

Incidentally, shareURL is not a configuration option that needs to be set in the gallery's embedding code.
It is used only by JuiceboxBuilder-Pro to set valid Open Graph meta tags in the gallery's 'index.html' web page.
shareURL is included in a gallery's 'config.xml' file simply so that JuiceboxBuilder-Pro can read it when the gallery is opened for editing.
(shareURL is not used by Juicebox when a gallery is displayed.)

7 (edited by mrp 2019-08-30 13:26:15)

Re: Content Security Policy and Juicebox

My test page https://stage.mrp.net/photos/travel/manila/ should illustrate what I'm seeing. I believe that I am using 1.5.1.

Re: Content Security Policy and Juicebox

Bugger my Lightroom plugin is claiming to be 1.4.4.1

Re: Content Security Policy and Juicebox

OK I have updated the juicebox.js file to 1.5.1 and it is still complaining.

Re: Content Security Policy and Juicebox

Thank you for providing the URL to your gallery's web page.

The <script> tag loading your 'juicebox-gallery.js' file is not closed and everything after it, up until the next closing </script> tag on your web page (including the 'juicebox-container' <div>), is being treated as JavaScript by the browser (so there is essentially no container on your web page for the gallery to be loaded into).
(Sorry I did not notice this in your post above. It was much easier to catch with syntax highlighting in my browser.)
Change:

<script src="/scripts/juicebox-gallery.js" id="juicebox" data-page="travel/manila">

... to:

<script src="/scripts/juicebox-gallery.js" id="juicebox" data-page="travel/manila"></script>

Hopefully this will resolve your problem.

11

Re: Content Security Policy and Juicebox

Thanks! That has fixed that problem. A second set of eyes is always helpful.
On Chrome I'm still seeing a problem listed (which Firefox doesn't mention)

VM6664:1 [Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive. See https://www.chromestatus.com/feature/5745543795965952

Also curiously the button bar is shorter on 1.5.1 and so wraps onto a second line, which is annoying.

Re: Content Security Policy and Juicebox

Thanks! That has fixed that problem.

That's great! Thank you for letting me know.

On Chrome I'm still seeing a problem listed (which Firefox doesn't mention)

I see the 'Violation' entries in Chrome when setting the debugging level to 'Verbose'.
Unfortunately, there is nothing that a user can do to address this as the code which the 'Violation' entries refer to is buried deep within the 'juicebox.js' JavaScript file which is obfuscated and cannot be modified.
However, I have notified the developers who will investigate the issue.

Also curiously the button bar is shorter on 1.5.1 and so wraps onto a second line, which is annoying.

The Button Bar should not wrap unless there is not enough space for all buttons to be displayed on a single line.
I have created a test gallery (using the same configuration options that your gallery uses) and the Button Bar does not wrap there.
I notice that your 'juicebox.js' file is now v1.5.1 but your 'theme.css' file ('/juicebox/jbcore/classic/theme.css') is still v1.4.4.
Please ensure that all files within your gallery's 'jbcore' folder are up-to-date (v1.5.1) by replacing the existing 'jbcore' folder on your web server with the 'jbcore' folder from the Juicebox-Pro v1.5.1 zip package ('juicebox_pro_1.5.1/web/jbcore').
This should hopefully solve your problem.

13

Re: Content Security Policy and Juicebox

Steven @ Juicebox wrote:

On Chrome I'm still seeing a problem listed (which Firefox doesn't mention)

I see the 'Violation' entries in Chrome when setting the debugging level to 'Verbose'.
Unfortunately, there is nothing that a user can do to address this as the code which the 'Violation' entries refer to is buried deep within the 'juicebox.js' JavaScript file which is obfuscated and cannot be modified.
However, I have notified the developers who will investigate the issue.

I figured it was hidden deep within the juicebox.js script and while it can be pretty printed I wasn't eager to go look.

Please ensure that all files within your gallery's 'jbcore' folder are up-to-date (v1.5.1) by replacing the existing 'jbcore' folder on your web server with the 'jbcore' folder from the Juicebox-Pro v1.5.1 zip package ('juicebox_pro_1.5.1/web/jbcore').
This should hopefully solve your problem.

Bugger missed that one. Now fixed too. Thanks for your help. Now to change all those references to the inline script :-)

Re: Content Security Policy and Juicebox

Thanks for your help.

You're welcome!

I figured it was hidden deep within the juicebox.js script and while it can be pretty printed I wasn't eager to go look.

Whilst you could technically decompress and pretty-print the 'jucebox.js' file, it still probably wouldn't make a lot a sense (a lot of descriptive variable names are changed in the compression process) and modification of the source code is not supported (see this FAQ). We'll need to wait for the developers on this one.

Now to change all those references to the inline script :-)

I hope you've not got too many to do!

15

Re: Content Security Policy and Juicebox

I hope you've not got too many to do!

198 down, 35 to go !

Re: Content Security Policy and Juicebox

I didn't realise that you had so many galleries! Hopefully you'll be finished by now.

I'm glad you've made the choice of having al your galleries share a single 'jbcore' folder (as documented here).
This will make updating all your galleries (when a new version of Juicebox is released) a simple matter of replacing just one 'jbcore' folder on your web server (instead of 233).
(I mention this just in case anyone else reading this thread also has a lot of galleries and is not aware that multiple galleries can share a single 'jbcore' folder.)

17

Re: Content Security Policy and Juicebox

Oh yes a single jbcore is a win. Of course after completing it I find I can't get rid of the 'unsafe-eval' in the policy

EvalError: call to eval() blocked by CSP juicebox.js:14:1

Re: Content Security Policy and Juicebox

I get a lot of errors on the javascript console such as

I realise that in an ideal world, it would be great to have no '[Violation]' entries in the console but it is worth remembering that these entries are only present in Chrome and only when the debugging level is set to 'Verbose'. (They are not classed as 'Errors', 'Warnings' or even 'Info'.)

Just out of curiosity, I loaded a few popular web pages into Chrome (adobe.com, amazon.com, apple.com, microsoft.com, mozilla.org) and they all display '[Violation]' entries (of one type or another, some more than others) in 'Verbose' mode.

Of course after completing it I find I can't get rid of the 'unsafe-eval' in the policy

That's down to the way that the 'juicebox.js' file is packed which is a choice that the developers have taken.

The 'juicebox.js' file uses eval() and CSP does not allow the use of eval() ("Eval and related functions are disabled") so, unfortunately, Juicebox will not be fully compatible with CSP guidelines.
There really is nothing that can be done about this (at user level) at the moment, although I have notified the developers of this so it is in their hands now.

19

Re: Content Security Policy and Juicebox

There really is nothing that can be done about this (at user level) at the moment, although I have notified the developers of this so it is in their hands now.

Yes I realise there is nothing I (or you) can do about it, I just wanted to flag it and hopefully the developers will consider the needs of people who want to implement content security.

Re: Content Security Policy and Juicebox

Thanks!

Edit:
For others reading this thread, although I have notified the developers, unless the 'juicebox.js' file is repacked using a different method, it will always trigger the Content Security Policy eval warning.
If you have a CSP in place and want to retain it whilst still allowing Juicebox to run, then you'll need to add 'unsafe-eval' to your CSP (and also 'unsafe-inline', too, if your gallery's embedding code is inline and not in an external JavaScript file.)
Relaxing the CSP to suppress warnings is not ideal by any means but I thought I should mention this in case it helps anyone.