Skip to content

Commit

Permalink
Allow webviews to be set as trusted viewers (#5592)
Browse files Browse the repository at this point in the history
* Allow webviews to be set as trusted viewers

Webviews can't set `ancestorOrigins` properly (maybe?), we can't use it
to tell if we are in a trusted viewer context. Instead, fall back to our
"old browser" path, which creates a `trustedViewerResolver_`. When the
webview's integration script [sets the message
deliverer](https://github.com/ampproject/amphtml/blob/f28e116/src/service/viewer-impl.js#L947),
it [will
resolve](https://github.com/ampproject/amphtml/blob/f28e116/src/service/viewer-impl.js#L961-L962)
to the webview's passed origin.

Fixes #5563.

* Add tests

* Do not trust "webviews" that are really bad actor iframes

We treat them like normal iframes.

* Test for '1' explicitly

* Fix test
  • Loading branch information
jridgewell committed Oct 14, 2016
1 parent ba6c425 commit 8bd195c
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 2 deletions.
11 changes: 9 additions & 2 deletions src/service/viewer-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,19 @@ export class Viewer {
this.performanceTracking_ = this.params_['csi'] === '1';
dev().fine(TAG_, '- performanceTracking:', this.performanceTracking_);

/**
* Whether the AMP document is embedded in a webview.
* @private @const {boolean}
*/
this.isWebviewEmbedded_ = !this.isIframed_ &&
this.params_['webview'] == '1';

/**
* Whether the AMP document is embedded in a viewer, such as an iframe or
* a web view.
* @private @const {boolean}
*/
this.isEmbedded_ = (this.isIframed_ || this.params_['webview'] === '1') &&
this.isEmbedded_ = (this.isIframed_ || this.isWebviewEmbedded_) &&
!this.win.AMP_TEST_IFRAME;

/** @private {boolean} */
Expand Down Expand Up @@ -295,7 +302,7 @@ export class Viewer {
// Not embedded in IFrame - can't trust the viewer.
trustedViewerResolved = false;
trustedViewerPromise = Promise.resolve(false);
} else if (this.win.location.ancestorOrigins) {
} else if (this.win.location.ancestorOrigins && !this.isWebviewEmbedded_) {
// Ancestors when available take precedence. This is the main API used
// for this determination. Fallback is only done when this API is not
// supported by the browser.
Expand Down
117 changes: 117 additions & 0 deletions test/functional/test-viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,123 @@ describe('Viewer', () => {
});
});

describe('when in webview', () => {
it('should decide trusted on connection with origin', () => {
windowApi.parent = windowApi;
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = [];
const viewer = new Viewer(ampdoc);
viewer.setMessageDeliverer(() => {}, 'https://google.com');
return viewer.isTrustedViewer().then(res => {
expect(res).to.be.true;
});
});

it('should NOT allow channel without origin', () => {
windowApi.parent = windowApi;
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = [];
const viewer = new Viewer(ampdoc);
expect(() => {
viewer.setMessageDeliverer(() => {});
}).to.throw(/message channel must have an origin/);
});

it('should decide non-trusted on connection with wrong origin', () => {
windowApi.parent = windowApi;
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = [];
const viewer = new Viewer(ampdoc);
viewer.setMessageDeliverer(() => {}, 'https://untrusted.com');
return viewer.isTrustedViewer().then(res => {
expect(res).to.be.false;
});
});

it('should NOT give precedence to ancestor', () => {
windowApi.parent = windowApi;
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = ['https://google.com'];
const viewer = new Viewer(ampdoc);
viewer.setMessageDeliverer(() => {}, 'https://untrusted.com');
return viewer.isTrustedViewer().then(res => {
expect(res).to.be.false;
});
});
});

describe('when in a fake webview (a bad actor iframe)', () => {
it('should consider trusted by ancestor', () => {
windowApi.parent = {};
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = ['https://google.com'];
return new Viewer(ampdoc).isTrustedViewer().then(res => {
expect(res).to.be.true;
});
});

it('should consider non-trusted without ancestor', () => {
windowApi.parent = {};
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = [];
return new Viewer(ampdoc).isTrustedViewer().then(res => {
expect(res).to.be.false;
});
});

it('should consider non-trusted with wrong ancestor', () => {
windowApi.parent = {};
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = ['https://untrusted.com'];
return new Viewer(ampdoc).isTrustedViewer().then(res => {
expect(res).to.be.false;
});
});

it('should decide trusted on connection with origin', () => {
windowApi.parent = {};
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = null;
const viewer = new Viewer(ampdoc);
viewer.setMessageDeliverer(() => {}, 'https://google.com');
return viewer.isTrustedViewer().then(res => {
expect(res).to.be.true;
});
});

it('should NOT allow channel without origin', () => {
windowApi.parent = {};
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = null;
const viewer = new Viewer(ampdoc);
expect(() => {
viewer.setMessageDeliverer(() => {});
}).to.throw(/message channel must have an origin/);
});

it('should decide non-trusted on connection with wrong origin', () => {
windowApi.parent = {};
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = null;
const viewer = new Viewer(ampdoc);
viewer.setMessageDeliverer(() => {}, 'https://untrusted.com');
return viewer.isTrustedViewer().then(res => {
expect(res).to.be.false;
});
});

it('should give precedence to ancestor', () => {
windowApi.parent = {};
windowApi.location.hash = '#webview=1';
windowApi.location.ancestorOrigins = ['https://google.com'];
const viewer = new Viewer(ampdoc);
viewer.setMessageDeliverer(() => {}, 'https://untrusted.com');
return viewer.isTrustedViewer().then(res => {
expect(res).to.be.true;
});
});
});

it('should trust domain variations', () => {
test('https://google.com', true);
test('https://www.google.com', true);
Expand Down

0 comments on commit 8bd195c

Please sign in to comment.