-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
amp-bind: Throw user error when replacing non-whitelisted URL vars #13081
amp-bind: Throw user error when replacing non-whitelisted URL vars #13081
Conversation
a8d94b4
to
5632ec8
Compare
5632ec8
to
959f430
Compare
/to @aghassemi @alabiaga |
* @return {!Promise<!Array<string>>} | ||
*/ | ||
collectUnwhitelistedVars(element) { | ||
const url = element.getAttribute('src'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const url only used once, just inline?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer this for readability and debuggability.
src/service/url-replacements-impl.js
Outdated
const url = element.getAttribute('src'); | ||
return this.collectVars(url).then(vars => { | ||
const whitelist = this.getWhitelistForElement_(element); | ||
return Object.keys(vars).filter(v => !whitelist[v]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just inline?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to change this to account for whitelist == undefined case.
extensions/amp-list/0.1/amp-list.js
Outdated
return fetchBatchedJsonFor(this.getAmpDoc(), this.element, itemsExpr); | ||
// Require opt-in for URL variable replacements on fetches triggered | ||
// by [src] mutation. @see spec/amp-var-substitutions.md | ||
const policy = (this.element.getAttribute('src') == this.initialSrc_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just compare the origin's and allow path and hash to differ? That would make it less of a breaking change and I don't see particular security concerns if origins match, but I might be wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right that this only matters for requests to non-pub-origins but I thought that would too specific to message gracefully. I'll try it out though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is done.
/** | ||
* @enum {number} | ||
*/ | ||
export const UrlReplacementPolicy = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Maybe FetchUrlReplacementPolicy
since the policy does not apply to other cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need to disambiguate here since none/opt-in/all does fit the system in general. E.g. <input>
and <a>
tags currently require opt-in, and some URL attributes don't support substitutions at all.
|
||
// Replace vars in URL if desired. | ||
const urlReplacements = Services.urlReplacementsForDoc(ampdoc); | ||
const srcPromise = (opt_urlReplacement >= UrlReplacementPolicy.OPT_IN) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the none
case, should they be replaced with ``? leaving them as is would generate strange and wrong Urls.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving it unmodified is the default behavior for other opt-ins, e.g. <a>
.
df5deb9
to
59f75a4
Compare
This pull request introduces 1 alert - view on lgtm.com new alerts:
Comment posted by lgtm.com |
This pull request introduces 1 alert - view on lgtm.com new alerts:
Comment posted by lgtm.com |
ee0e0fb
to
c04f81a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comments everyone.
* @return {!Promise<!Array<string>>} | ||
*/ | ||
collectUnwhitelistedVars(element) { | ||
const url = element.getAttribute('src'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer this for readability and debuggability.
src/service/url-replacements-impl.js
Outdated
const url = element.getAttribute('src'); | ||
return this.collectVars(url).then(vars => { | ||
const whitelist = this.getWhitelistForElement_(element); | ||
return Object.keys(vars).filter(v => !whitelist[v]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had to change this to account for whitelist == undefined case.
extensions/amp-list/0.1/amp-list.js
Outdated
return fetchBatchedJsonFor(this.getAmpDoc(), this.element, itemsExpr); | ||
// Require opt-in for URL variable replacements on fetches triggered | ||
// by [src] mutation. @see spec/amp-var-substitutions.md | ||
const policy = (this.element.getAttribute('src') == this.initialSrc_) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is done.
|
||
// Replace vars in URL if desired. | ||
const urlReplacements = Services.urlReplacementsForDoc(ampdoc); | ||
const srcPromise = (opt_urlReplacement >= UrlReplacementPolicy.OPT_IN) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaving it unmodified is the default behavior for other opt-ins, e.g. <a>
.
/** | ||
* @enum {number} | ||
*/ | ||
export const UrlReplacementPolicy = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we don't need to disambiguate here since none/opt-in/all does fit the system in general. E.g. <input>
and <a>
tags currently require opt-in, and some URL attributes don't support substitutions at all.
@@ -48,7 +48,7 @@ The following table lists the features that enable variable substitutions, as we | |||
<tr> | |||
<td width="25%"><code>amp-list</code><br><a href="https://github.com/ampproject/amphtml/blob/master/extensions/amp-list/amp-list.md#substitutions">Detailed documentation</a></td> | |||
<td width="25%">Requests must be HTTPS URLs (not a requirement specific to variable substitutions)</td> | |||
<td width="25%">No</td> | |||
<td width="25%">Yes, if fetching cross-origin resources via <code>[src]</code> <a href="https://www.ampproject.org/docs/reference/components/amp-bind#element-specific-attributes">attribute binding</a>. Otherwise, no. Read more about <a href="#per-use-opt-in">per-use opt-in</a></td> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bpaduch Would like your input on whether this is confusing or not.
user().error(TAG, 'URL variable substitutions in CORS fetches ' + | ||
'triggered by amp-bind will soon require opt-in. Please add ' + | ||
`data-amp-replace="${unwhitelisted.join(' ')}" to the ` + | ||
`<${TAG}> element. See "bit.ly/amp-var-subs" for details.`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bpaduch Ditto.
@ericlindley-g FYI adding a user error for new opt-in requirement in preparation for two-way amp-frame messaging. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docs are good.
Thanks for the heads up! Could you refresh my memory on the end-to-end path for this to give developers notice before an error is triggered that invalidates the page or breaks functionality? (e.g. Validation warning -> error) |
#12498 lists all the steps you suggested. This PR will only show a user error in dev console but retain current functionality. After deployment, we'll see how common this is in the wild via our error logs and can decide next steps from there. |
Perfect — thanks! (I knew I had seen those somewhere :) |
…mpproject#13081) * first pass at user().error for future opt-in requirement * url replacements unit test * rename to batchFetchJsonFor and add test-batched-json * lint fixes, use enum for replacement policy * refine docs * fix lint * use opt-in policy for amp-bind mutations only, fix types * more lint fixes * only require opt-in for CORS * fix collectUnwhitelistedVars for elements with no whitelist * refine error message * fix string error, thanks lgtm
…mpproject#13081) * first pass at user().error for future opt-in requirement * url replacements unit test * rename to batchFetchJsonFor and add test-batched-json * lint fixes, use enum for replacement policy * refine docs * fix lint * use opt-in policy for amp-bind mutations only, fix types * more lint fixes * only require opt-in for CORS * fix collectUnwhitelistedVars for elements with no whitelist * refine error message * fix string error, thanks lgtm
Step 1 for #12498.
opt_urlReplacement
fetchBatchedJsonFor
tobatchFetchJsonFor
Aside: I think we should merge batched-json.js into batched-xhr.js. It'll also make stubbing the function possible.