Skip to content

Commit

Permalink
release 0.0.4, window.location and document.location simulation
Browse files Browse the repository at this point in the history
  • Loading branch information
sashafir committed Mar 2, 2018
1 parent 1df4b17 commit 4248bd9
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 37 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ WebComponent acting as IFRAME.

[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://www.webcomponents.org/element/EPA-WG/embed-page)

## Security
* General browser and application [security improvements overview](security.md).

The scope insulation for DOM and CSS is done by WebComponet shadow dom, API for JS
are insulated by closure for global objects with wrappers limiting the dom access root
to component content. Similar approach will be applied for url, storage, cookies, etc.
Expand All @@ -18,8 +21,8 @@ The content could be set either by **src** attribute or by Polymer {{data}} bind
```

## To see in action
See the live basic [DEMO](https://raw-dot-custom-elements.appspot.com/EPA-WG/embed-page/v0.0.3/embed-page/demo/index.html)
, or check the [demo page on webcomponents.org](https://www.webcomponents.org/element/EPA-WG/embed-page/demo/demo/index.html)
See the live basic [DEMO](https://raw-dot-custom-elements.appspot.com/EPA-WG/embed-page/v0.0.4/embed-page/demo/index.html)
, check the [demo page on webcomponents.org](https://www.webcomponents.org/element/EPA-WG/embed-page/demo/demo/index.html)
, or locally run
```bash
$ polymer serve --open
Expand Down
16 changes: 14 additions & 2 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
<custom-style>
<style is="custom-style" include="demo-pages-shared-styles"></style>
</custom-style>
<style>iframe{width: 100%;}
<style>@import "page.css";
iframe{width: 100%;}
.CodeMirror{height: auto;}
fieldset{display: inline-block; border-bottom: none; border-right: none;}
embed-page{ box-shadow: inset 0 0 2em #000000; padding: 1em; }
Expand Down Expand Up @@ -97,7 +98,12 @@ <h1>Default style header</h1>
<li> <input id="external" class="external" type="checkbox" >
<button for="external">Toggle</button> checked by <var>page.js</var> </li>
</ul>
<script src="page.js" ></script>
<br/><label>window.location: <input class="win-location" />
<input type="button" value="get"/><input type="button" value="set"/> </label>
<br/><label>document.location: <input class="doc-location" />
<input type="button" value="get"/><input type="button" value="set"/> </label>

<script src="page.js" ></script>
<h3>Visual demo</h3>
<pre>
CSS
Expand All @@ -110,6 +116,12 @@ <h3>Visual demo</h3>
1. Click on link will replace the component content with page from <var>href</var> attribute.
Form
1. GET and POST will replace content according to FORM <var>action</var> attribute.
window.location & document.location
1. page in component populates text box with value matching SRC attribute of component.
2. clear the text box, click on GET. The full URL matching SRC attribute
should be placed in text box
3. change text box to <var>page-purple.html</var>, click on SET. The content of component
should load the page
</pre>
</div>
<div style="display: inline-block">
Expand Down
9 changes: 8 additions & 1 deletion demo/page-purple.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ <h1>Purple header</h1>
<input type="submit" value="POST" />
</form>
</fieldset>
<p>Extra line to show the DOM resizing when switching the pages within &lt;embed-page /&gt; component.</p>
<br/><label>window.location: <input class="win-location" />
<input type="button" value="get"/><input type="button" value="set"/> </label>
<br/><label>document.location: <input class="doc-location" />
<input type="button" value="get"/><input type="button" value="set"/> </label>

<script>document.getElementById("embedded").checked=true;</script>
<script src="page.js" ></script>
<style>@import "page.css";</style>

<p>Extra line to show the DOM resizing when switching the pages within &lt;embed-page /&gt; component.</p>
7 changes: 7 additions & 0 deletions demo/page-violet.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ <h1>Violet header</h1>
<input type="submit" value="POST" />
</form>
</fieldset>
<br/><label>window.location: <input class="win-location" />
<input type="button" value="get"/><input type="button" value="set"/> </label>
<br/><label>document.location: <input class="doc-location" />
<input type="button" value="get"/><input type="button" value="set"/> </label>

<script>document.getElementById("embedded").checked=false;</script>
<script src="page.js" ></script>
<style>@import "page.css";</style>


2 changes: 2 additions & 0 deletions demo/page.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.win-location,
.doc-location{width: 100%;}
17 changes: 14 additions & 3 deletions demo/page.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
let cb = document.getElementById("external");
cb.checked=true;
document.getElementById("external").checked=true;
[...document.getElementsByTagName('button')].forEach( b => b.onclick = ()=>ToggleCb(b) );

function ToggleCb( b )
{ let a = document.getElementsByClassName( b.getAttribute('for') );
for( let x of a )
x.checked = !x.checked;
}
}
const $ = css => document.querySelector(css)
, winLocation = $('.win-location')
, docLocation = $('.doc-location');


winLocation.value = window.location;
docLocation.value = document.location;
document.querySelector('.win-location~*[value=get]').onclick = x => winLocation.value = window.location;
document.querySelector('.doc-location~*[value=get]').onclick = x => docLocation.value = document.location;
document.querySelector('.win-location~*[value=set]').onclick = x => window.location = winLocation.value ;
document.querySelector('.doc-location~*[value=set]').onclick = x => document.location = docLocation.value ;

64 changes: 35 additions & 29 deletions embed-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,31 @@
, FRAME_BLANK = "about:blank";
let GBL_InstancesCount = 0;

class EpaLocationHolder
{
constructor( app, a )
{
this.getLocation = x=> a;
this.setLocation = v=> app.src = v;
}
get location( ){ return this.getLocation() }
set location(v){ return this.setLocation( v ) }
}
class EpaDocument extends EpaLocationHolder
{
constructor( app, f, a )
{
super( app, a );
Object.assign( this,
{ getElementById : x=> $( '#'+x, f )[0]
, getElementsByTagName : x=> $( x, f )
, getElementsByClassName : x=> f.getElementsByClassName( x )
, createElement : x=> doc.createElement(x)
, querySelectorAll : x=> f.querySelectorAll(x)
, querySelector : x=> f.querySelector(x)
})
}
}
/**
* `embed-page`
* embeds page in iframe fashion but using shadow dom for CSS and dom insulation and closure for JS jailing.
Expand All @@ -29,6 +54,7 @@
*/
class EmbedPage extends Polymer.Element
{

static get is() { return 'embed-page' }

static get properties()
Expand Down Expand Up @@ -66,17 +92,15 @@
onBeforeFetch(){ addClass ( this.$f,'loading') }
onAfterFetch (){ removeClass( this.$f,'loading') }


get context()
{ const f = this.$.framed;
return { window : win
, document : { getElementById: id => $( '#'+id, f )[0]
, getElementsByTagName: x => $( x, f )
, getElementsByClassName: x => f.getElementsByClassName( x )
, createElement : x=> doc.createElement(x)
, querySelectorAll: x=> f.querySelectorAll(x)
, querySelector : x=> f.querySelector(x)
, location: { protocol : doc.location.protocol }
}
{ const f = this.$.framed
, a = doc.createElement('a');
a.href = this.src;
a.toString = function(){ return this.href }

return { window : new EpaLocationHolder(this,a)
, document : new EpaDocument(this,f,a)
, head : doc.head
, body : doc.body
}
Expand Down Expand Up @@ -128,15 +152,6 @@
}
const scriptsSelector = 'script:not([type]),script[type="application/javascript"],script[type="text/javascript"]';

//ajax('https://www.cahousefinder.com/wp-includes/js/jquery/jquery.js?ver=1.11.0','GET').then(
// x=>{
// debugger;
// },
// err=>{
// debugger;
// }
//);

//if ('serviceWorker' in navigator)
// //navigator.serviceWorker.register('https://cdn.xml4jquery.com/ajax/poc/sw.js' // not allowed as page has different origin
// navigator.serviceWorker.register('sw.js'
Expand All @@ -148,16 +163,7 @@
// log("Error", err);
// });

//fetch( 'https://www.cahousefinder.com/wp-includes/js/jquery/jquery.js?ver=1.11.0', { mode: 'no-cors' } )
//.then( r => r.text() )
//.then(
// x=>{
// debugger;
// },
// err=>{
// debugger;
// }
//);


win.customElements.define( EmbedPage.is, EmbedPage );

Expand Down
19 changes: 19 additions & 0 deletions security.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# EPA browser and application security improvement overview

Current standards stack provides a little for 3rd party UI integration into web page.
In order to allocate some space in page for 3rd party app content host page either
* should suffer from IFRAME limitations or
* compromise own security by injecting 3rd party JS into page.

\<embed-page\> has given a flexibility of embedded DOM and IFRAME kind of browsing
context insulation.

Unlike direct injection of 3rd party script EPA executes JS in host page with
insulation layer preventing access to document, window and major APIs.

\<embed-page\> at this stage yet a proof of concept for
[Embeddable Progressive Application](https://github.com/EPA-WG/EPA-concept) and potentially
the polyfill for standard-to-be implemented natively by browser with all security concerns addressed.



0 comments on commit 4248bd9

Please sign in to comment.