Skip to content

Commit

Permalink
Whitelist actions on the special AMP target (#13192)
Browse files Browse the repository at this point in the history
* respect the whitelist of actions specified in meta tags

* fixed the failing tests

* lint fix

* Fixed some of the concerns in the review

* Faking the window

* ran lint --fix

* simplifying the functional tests

* more code review fixes

* using real window in test

* a few suggestions by Su

* fixing import orders

* fixed lint errors

* removing const identifier
  • Loading branch information
hamousavi authored and William Chou committed Feb 23, 2018
1 parent c56637b commit 19e6e78
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 2 deletions.
39 changes: 38 additions & 1 deletion src/service/standard-actions-impl.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,42 @@ export class StandardActions {
/** @const @private {!./viewport/viewport-impl.Viewport} */
this.viewport_ = Services.viewportForDoc(ampdoc);

/** @private {?Array<string>} */
this.ampActionWhitelist_ = null;

this.installActions_(this.actions_);
}

/**
* Searches for a meta tag containing whitelist of actions on
* the special AMP target, e.g.,
* <meta name="amp-action-whitelist" content="AMP.setState,AMP.pushState">
* @return {?Array<string>} the whitelist of actions on the special AMP target.
* @private
*/
getAmpActionWhitelist_() {
if (this.ampActionWhitelist_) {
return this.ampActionWhitelist_;
}

const head = this.ampdoc.getRootNode().head;
if (!head) {
return null;
}
// A meta[name="amp-action-whitelist"] tag, if present, contains,
// in its content attribute, a whitelist of actions on the special AMP target.
const meta =
head.querySelector('meta[name="amp-action-whitelist"]');
if (!meta) {
return null;
}

this.ampActionWhitelist_ = meta.getAttribute('content').split(',')
.map(action => action.trim());
return this.ampActionWhitelist_;
}


/** @override */
adoptEmbedWindow(embedWin) {
this.installActions_(Services.actionServiceForDoc(embedWin.document));
Expand Down Expand Up @@ -100,10 +133,14 @@ export class StandardActions {
* @param {number=} opt_actionIndex
* @param {!Array<!./action-impl.ActionInfoDef>=} opt_actionInfos
* @return {?Promise}
* @throws {Error} If action is not recognized.
* @throws {Error} If action is not recognized or is not whitelisted.
*/
handleAmpTarget(invocation, opt_actionIndex, opt_actionInfos) {
const method = invocation.method;
if (this.getAmpActionWhitelist_() &&
!this.getAmpActionWhitelist_().includes(`AMP.${method}`)) {
throw user().createError(`AMP.${method} is not whitelisted.`);
}
switch (method) {
case 'pushState':
case 'setState':
Expand Down
53 changes: 52 additions & 1 deletion test/functional/test-standard-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import {AmpDocSingle} from '../../src/service/ampdoc-impl';
import {OBJECT_STRING_ARGS_KEY} from '../../src/service/action-impl';
import {Services} from '../../src/services';
import {StandardActions} from '../../src/service/standard-actions-impl';
import {createElementWithAttributes} from '../../src/dom';
import {installHistoryServiceForDoc} from '../../src/service/history-impl';
import {setParentWindow} from '../../src/service';


describes.sandboxed('StandardActions', {}, () => {
let standardActions;
let mutateElementStub;
Expand Down Expand Up @@ -346,6 +346,57 @@ describes.sandboxed('StandardActions', {}, () => {
});
});

describes.realWin('whitelist of actions on the special AMP target', {
amp: {
ampdoc: 'single',
},
}, env => {
beforeEach(() => {
env.win.document.head.appendChild(
createElementWithAttributes(env.win.document, 'meta', {
name: 'amp-action-whitelist',
content: 'AMP.pushState,AMP.setState',
}));
});

it('should not implement print when not whitelisted', () => {
standardActions = new StandardActions(env.ampdoc);

const windowApi = {
print: () => {},
};
const printStub = sandbox.stub(windowApi, 'print');
const invocation = {
method: 'print',
satisfiesTrust: () => true,
target: {
ownerDocument: {
defaultView: windowApi,
},
},
};
expect(() => standardActions.handleAmpTarget(invocation)).to.throw();
expect(printStub).to.not.be.called;
});

it('should implement pushState when whitelisted', () => {
standardActions = new StandardActions(env.ampdoc);

const handleAmpBindActionStub =
sandbox.stub(standardActions, 'handleAmpBindAction_');
const invocation = {
method: 'pushState',
satisfiesTrust: () => true,
target: env.ampdoc,
};

expect(() =>
standardActions.handleAmpTarget(invocation, 0, [])).to.not.throw();
expect(handleAmpBindActionStub).to.be.calledOnce;
});

});

describes.fakeWin('adoptEmbedWindow', {}, env => {
let embedWin;
let embedActions;
Expand Down

0 comments on commit 19e6e78

Please sign in to comment.