Greenheart / pagecrypt

Password Protected Single Page Applications and HTML files
GNU Affero General Public License v3.0
242 stars 26 forks source link

Investigate ways to execute the app bundle in the top level document without using an <iframe> with the `srcdoc` attribute #13

Closed Greenheart closed 3 years ago

Greenheart commented 3 years ago

Up until this point, pagecrypt has used the srcdoc attribute om <iframe> elements. This has mostly worked well for simple apps and websites, but severely limited advanced apps to use pagecrypt.

By removing the <iframe> and also stop using the srcdoc attribute, we could bypass these restrictions.

This would enable apps to use the full web platform instead of just using a small subset, which in turn would would make pagecrypt more valuable. For example, this would enable developers to deploy SPA:s with routing and similar features currently not supported in the <iframe> when using srcdoc.

Need to investigate potential solutions further, but here are some initial ideas:

Greenheart commented 3 years ago
var inputHTML = `<!DOCTYPE html>
<html>
<head>
  <title>hello from parsed code</title>
</head>
<body>
<script>

localStorage.hello = 'hello there!'
console.log(localStorage.hello)

</script>
</body>
</html>`
var parser = new DOMParser();
var parsedDocument = parser.parseFromString(inputHTML, 'text/html');

// set the current page's <html> contents to the newly parsed <html> content
document.getElementsByTagName('html')[0].innerHTML = parsedDocument.getElementsByTagName('html')[0].innerHTML;

// get a list of all <script> tags in the new page
var tmpScripts = document.getElementsByTagName('script');
if (tmpScripts.length > 0) {
    // push all of the document's script tags into an array
    // (to prevent dom manipulation while iterating over dom nodes)
    var scripts = [];
    for (var i = 0; i < tmpScripts.length; i++) {
        scripts.push(tmpScripts[i]);
    }

    // iterate over all script tags and create a duplicate tags for each
    for (var i = 0; i < scripts.length; i++) {
        var s = document.createElement('script');
        s.innerHTML = scripts[i].innerHTML;

        // add the new node to the page
        scripts[i].parentNode.appendChild(s);

        // remove the original (non-executing) node from the page
        scripts[i].parentNode.removeChild(scripts[i]);
    }
}

based on: https://stackoverflow.com/a/22997909/4183985

Greenheart commented 3 years ago

fixed in 4.0.0