-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
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
feat(web): Integrate trusted types into Vue #10491
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* @flow */ | ||
import Vue from 'core/index' | ||
import {getTrustedTypes, isTrustedValue} from 'shared/util' | ||
|
||
type TrustedTypePolicy = { | ||
// value returned is actually an object with toString method returning the wrapped value | ||
createHTML: (value: any) => string; | ||
}; | ||
|
||
let policy: ?TrustedTypePolicy | ||
// create policy lazily to simplify testing | ||
function getOrCreatePolicy() { | ||
const tt = getTrustedTypes() | ||
if (tt && !policy) { | ||
policy = tt.createPolicy(Vue.config.trustedTypesPolicyName, {createHTML: (s) => s}); | ||
} | ||
|
||
return policy | ||
} | ||
|
||
if (process.env.NODE_ENV !== 'production') { | ||
// we need this function to clear the policy in tests | ||
Vue.prototype.$clearTrustedTypesPolicy = function() { | ||
policy = undefined | ||
} | ||
} | ||
|
||
export function maybeCreateDangerousSvgHTML(value: any): string { | ||
const tt = getTrustedTypes() | ||
|
||
if (!tt || !isTrustedValue(value)) return `<svg>${value}</svg>`; | ||
// flow complains that 'getOrCreatePolicy()' might return null | ||
else return (getOrCreatePolicy(): any).createHTML(`<svg>${value}</svg>`); | ||
} | ||
|
||
export function getTrustedShouldDecodeInnerHTML(href: boolean): string { | ||
const html = href ? `<a href="\n"/>` : `<div a="\n"/>`; | ||
const p = getOrCreatePolicy() | ||
if (!p) return html; | ||
else return p.createHTML(html); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -79,15 +79,35 @@ export function isPromise (val: any): boolean { | |
) | ||
} | ||
|
||
let trustedTypes = undefined | ||
export function getTrustedTypes() { | ||
if (trustedTypes === undefined) { | ||
// TrustedTypes have been renamed to trustedTypes https://github.com/WICG/trusted-types/issues/177 | ||
trustedTypes = typeof window !== 'undefined' ? (window.trustedTypes || window.TrustedTypes) : null; | ||
} | ||
return trustedTypes; | ||
} | ||
|
||
export function isTrustedValue(value: any): boolean { | ||
const tt = getTrustedTypes(); | ||
if (!tt) return false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, it will be available natively in browsers (for now just chrome with For this function it's logical to return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. EDIT: The code before was not compliant with what I said as I would throw and error in a specific case (innerHTML in svg in IE with trustedTypes available). I've fixed the code not to throw in this case. |
||
// TrustedURLs are deprecated and will be removed soon: https://github.com/WICG/trusted-types/pull/204 | ||
else return tt.isHTML(value) || tt.isScript(value) || tt.isScriptURL(value) || (tt.isURL && tt.isURL(value)) | ||
} | ||
|
||
/** | ||
* Convert a value to a string that is actually rendered. | ||
*/ | ||
export function toString (val: any): string { | ||
return val == null | ||
? '' | ||
: Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) | ||
? JSON.stringify(val, null, 2) | ||
: String(val) | ||
if (isTrustedValue(val)) { | ||
return val; | ||
} else { | ||
return val == null | ||
? '' | ||
: Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) | ||
? JSON.stringify(val, null, 2) | ||
: String(val) | ||
} | ||
} | ||
|
||
/** | ||
|
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 line is called when users use object bindings, e.g.
v-bind="obj"
, and the new object has different keys from the old object. For example, on first renderobj
could be{ id: 'foo' }
and later updated to{ innerHTML: 'bar' }
- in this caseid
needs to be unset. This can also happen in manually written render functions.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, however I don't think I understand.
The
props
andoldProps
are domProps from render function andv-bind
binds values from data property of the Vue component. I am still unable to trigger that part of the code, but I was trying to do something like this codesandbox. I also had a look at the original issue here, but their example is different from what I want to see.The important question is: Can the code (where the TODO comment is) be called for dangerous properties like
innerHTML
?If yes, I need to add integration on this place as well, but I don't wanna include it on places which don't need it.