Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove inline javascript to comply with some CSP #249

Closed
mossroy opened this issue Jan 5, 2022 · 9 comments · Fixed by #273
Closed

Remove inline javascript to comply with some CSP #249

mossroy opened this issue Jan 5, 2022 · 9 comments · Fixed by #273

Comments

@mossroy
Copy link

mossroy commented Jan 5, 2022

Tested with https://download.kiwix.org/zim/stack_exchange/beer_stackexchange_com_2021-12.zim

There are these 2 inline javascript blocks in each page :

        <script type="text/javascript">
            /*
             * replace an <img/> node with a jdidenticon <svg />
             * Uses it's parent .innerHTML so img should be wrapped.
             * @param img: either an HTMLImageElement or an Error event
             */
            function replaceWithJdenticon(img) {
                if (!(img instanceof HTMLImageElement)) {
                    img = img.srcElement;
                }
                if (img.getAttribute('data-jdenticon-value') || img.getAttribute('data-jdenticon-hash')) {
                    img.parentNode.innerHTML = jdenticon.toSvg(img.getAttribute('data-jdenticon-value') || img.getAttribute('data-jdenticon-hash'), img.width || img.getAttribute("data-jdenticon-width"));
                }
            }
            var webp_handler = new WebPHandler({
                on_error: replaceWithJdenticon,
                scripts_urls: ["./static/js/webp-hero.polyfill.js", "./static/js/webp-hero.bundle.js"],
            });

            /*
             * manually set (in-templates) on all <img /> nodes so that any error loading
             * it by the browser calls it. Used to trigger polyfill and jdenticon fallback
             * /!\ requires WebPHandler to be ready _before_ the browser attempts to 
             * load any image in the page. WebP Hero scripts should thus be included
             * syncrhonously before this */
            function onImageLoadingError(img) {
                if (img === undefined)
                    return;

                // only use polyfill if browser lacks Webp supports and wasn't already polyfied
                // polyfill replaces url with data URI
                if (!webp_handler.supports_webp && img.src.length > 0 && img.src.substr(0, 5) != "data:") {
                    webp_handler.polyfillImage(img);
                    return;
                }

                // defaults to rendering as Jdenticon
                replaceWithJdenticon(img);
            }
        </script>
        <script>
            /* replace <time class="fromnow" /> with human delta between `datetime` attr and now */
            document.addEventListener('DOMContentLoaded', function(){
                var time_elements = document.querySelectorAll("time.fromnow");
                for (var i=0; i<time_elements.length; i++) {
                    time_elements[i].innerHTML = moment(time_elements[i].getAttribute("datetime")).fromNow();
                }
            });
        </script>

and the avatar images have the following attribute, too :
onerror="onImageLoadingError(this);"

@stale
Copy link

stale bot commented Apr 16, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be now be reviewed manually. Thank you for your contributions.

@stale stale bot added the stale label Apr 16, 2022
@stale stale bot removed the stale label May 26, 2022
@kelson42
Copy link
Contributor

@rgaudin Is that feasible? easily?

@kelson42 kelson42 added this to the 2.1.0 milestone May 26, 2022
@rgaudin
Copy link
Member

rgaudin commented May 26, 2022

There are additional ones, like MathJax, highlighting and for the tags browser. So yes, it's feasible, probably easy but time consuming…

@mossroy
Copy link
Author

mossroy commented Aug 3, 2022

Could you give us a link to a ZIM file we could test with?

@kelson42
Copy link
Contributor

kelson42 commented Aug 4, 2022

@mossroy
Copy link
Author

mossroy commented Aug 4, 2022

The inline javascript already identified has indeed disappeared.
But I found another inline javascript block in "tags" page (line 519):

<script type="text/javascript">
    // helper for enabling IE 8 event bindings
    function addEvent(el, type, handler) {
        if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler);
    }

    // live binding helper
    function live(selector, event, callback, context) {
        addEvent(context || document, event, function(e) {
            var found, el = e.target || e.srcElement;
            while (el && !(found = el.id == selector)) el = el.parentElement;
            if (found) callback.call(el, e);
        });
    }

    function createTagCard(tagName, nbQuestions) {
        let elem = document.createElement("div");
        elem.className = 's-card js-tag-cell grid fd-column suggested';
        elem.innerHTML = '<div class="grid jc-space-between ai-center mb12"><div class="grid--cell"><a href="./questions/tagged/__TAG__" class="post-tag" title="show questions tagged \'__TAG__\'" rel="tag">__TAG__</a></div></div><div class="mt-auto grid jc-space-between fs-caption fc-black-400"><div class="grid--cell">__NB_QUESTIONS__ question__QUESTIONS_PLURAL__</div></div>'.replaceAll('__TAG__', tagName).replaceAll('__NB_QUESTIONS__', nbQuestions).replaceAll('__QUESTIONS_PLURAL__', (nbQuestions == 1) ? '' : 's');
        return elem;
    }
    var tagfilterEle = document.getElementById("tagfilter");
    var tagsBrowserEle = document.getElementById("tags-browser");
    document.addEventListener('DOMContentLoaded', function() {
        window.tags = [];
        console.log('Registering tag filter');
        fetch("api/tags.json")
            .then(response => {
                return response.json();
            }).then(function (data){
                window.tags = data;
                live(tagfilterEle.id, 'input', function() {
                    let search = tagfilterEle.value.toLowerCase().trim();
                    let matchingTags = [];
                    console.log('input changed to', search);

                    // hide static items unless we have no search
                    if (search.length) {
                        console.log("search, hiding originals");
                        document.querySelectorAll("div.original").forEach(function (elem) {
                            if (elem.className.indexOf('d-none') == -1)
                                elem.className += ' d-none';
                        });
                    } else {
                        console.log("search cleared, restoring originals");
                        document.querySelectorAll("div.original").forEach(function (elem) {
                            elem.className = elem.className.replace(' d-none', '');
                        });
                    }

                    if (search.length) {
                        matchingTags = window.tags.filter(function (item) {
                            return (~item[0].indexOf(search));
                        }).slice(0, 36); // max 36 elems
                    }

                    // first remove previous results
                    console.log("removing suggesteds");
                    document.querySelectorAll("div.suggested").forEach(function (elem) {
                        elem.parentNode.removeChild(elem);
                    });

                    if (matchingTags.length) {
                        console.log("matches, appending results", matchingTags.length);
                        matchingTags.forEach(function (item) {
                            tagsBrowserEle.appendChild(createTagCard(item[0], item[1]));
                        });
                    }
                });
            });
    });
</script>

@rgaudin
Copy link
Member

rgaudin commented Aug 4, 2022

Fixed in 5cfce66. I'll share another ZIM

@rgaudin
Copy link
Member

rgaudin commented Aug 4, 2022

@mossroy
Copy link
Author

mossroy commented Aug 4, 2022

Looks good, now. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants