Skip to content

Commit b5b7345

Browse files
committed
1 parent e3a96f0 commit b5b7345

11 files changed

+189
-392
lines changed

dom/base/Element.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,6 +1674,80 @@ already_AddRefed<nsIPrincipal> Element::CreateDevtoolsPrincipal() {
16741674
return dtPrincipal.forget();
16751675
}
16761676

1677+
void Element::SetAttribute(
1678+
const nsAString& aName,
1679+
const TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString& aValue,
1680+
nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError) {
1681+
aError = nsContentUtils::CheckQName(aName, false);
1682+
if (aError.Failed()) {
1683+
return;
1684+
}
1685+
1686+
nsAutoString nameToUse;
1687+
const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
1688+
if (!name) {
1689+
RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(nameToUse);
1690+
Maybe<nsAutoString> compliantStringHolder;
1691+
const nsAString* compliantString =
1692+
TrustedTypeUtils::GetTrustedTypesCompliantAttributeValue(
1693+
*this, nameAtom, kNameSpaceID_None, aValue, compliantStringHolder,
1694+
aError);
1695+
if (aError.Failed()) {
1696+
return;
1697+
}
1698+
aError = SetAttr(kNameSpaceID_None, nameAtom, *compliantString,
1699+
aTriggeringPrincipal, true);
1700+
return;
1701+
}
1702+
1703+
Maybe<nsAutoString> compliantStringHolder;
1704+
RefPtr<nsAtom> attributeName = name->LocalName();
1705+
nsMutationGuard guard;
1706+
const nsAString* compliantString =
1707+
TrustedTypeUtils::GetTrustedTypesCompliantAttributeValue(
1708+
*this, attributeName, name->NamespaceID(), aValue,
1709+
compliantStringHolder, aError);
1710+
if (aError.Failed()) {
1711+
return;
1712+
}
1713+
if (!guard.Mutated(0)) {
1714+
aError = SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
1715+
*compliantString, aTriggeringPrincipal, true);
1716+
return;
1717+
}
1718+
1719+
// GetTrustedTypesCompliantAttributeValue may have modified mAttrs and made
1720+
// the result of InternalGetAttrNameFromQName above invalid. It may now return
1721+
// a different value, perhaps a nullptr. To be safe, just call the version of
1722+
// Element::SetAttribute accepting a string value.
1723+
SetAttribute(aName, *compliantString, aTriggeringPrincipal, aError);
1724+
}
1725+
1726+
void Element::SetAttributeNS(
1727+
const nsAString& aNamespaceURI, const nsAString& aQualifiedName,
1728+
const TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString& aValue,
1729+
nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError) {
1730+
RefPtr<mozilla::dom::NodeInfo> ni;
1731+
aError = nsContentUtils::GetNodeInfoFromQName(
1732+
aNamespaceURI, aQualifiedName, mNodeInfo->NodeInfoManager(),
1733+
ATTRIBUTE_NODE, getter_AddRefs(ni));
1734+
if (aError.Failed()) {
1735+
return;
1736+
}
1737+
1738+
Maybe<nsAutoString> compliantStringHolder;
1739+
RefPtr<nsAtom> attributeName = ni->NameAtom();
1740+
const nsAString* compliantString =
1741+
TrustedTypeUtils::GetTrustedTypesCompliantAttributeValue(
1742+
*this, attributeName, ni->NamespaceID(), aValue,
1743+
compliantStringHolder, aError);
1744+
if (aError.Failed()) {
1745+
return;
1746+
}
1747+
aError = SetAttr(ni->NamespaceID(), ni->NameAtom(), ni->GetPrefixAtom(),
1748+
*compliantString, aTriggeringPrincipal, true);
1749+
}
1750+
16771751
void Element::SetAttributeDevtools(const nsAString& aName,
16781752
const nsAString& aValue,
16791753
ErrorResult& aError) {

dom/base/Element.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ class Grid;
235235
class OwningTrustedHTMLOrNullIsEmptyString;
236236
class TrustedHTML;
237237
class TrustedHTMLOrNullIsEmptyString;
238+
class TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString;
238239

239240
// IID for the dom::Element interface
240241
#define NS_ELEMENT_IID \
@@ -1253,6 +1254,22 @@ class Element : public FragmentOrElement {
12531254
ErrorResult& aError) {
12541255
SetAttribute(aName, aValue, nullptr, aError);
12551256
}
1257+
1258+
MOZ_CAN_RUN_SCRIPT void SetAttribute(
1259+
const nsAString& aName,
1260+
const TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString& aValue,
1261+
nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError);
1262+
MOZ_CAN_RUN_SCRIPT void SetAttributeNS(
1263+
const nsAString& aNamespaceURI, const nsAString& aLocalName,
1264+
const TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString& aValue,
1265+
nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError);
1266+
MOZ_CAN_RUN_SCRIPT void SetAttribute(
1267+
const nsAString& aName,
1268+
const TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString& aValue,
1269+
ErrorResult& aError) {
1270+
SetAttribute(aName, aValue, nullptr, aError);
1271+
}
1272+
12561273
/**
12571274
* This method creates a principal that subsumes this element's NodePrincipal
12581275
* and which has flags set for elevated permissions that devtools needs to

dom/security/trusted-types/TrustedTypeUtils.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "mozilla/dom/TrustedScriptURL.h"
1919
#include "mozilla/dom/TrustedTypePolicy.h"
2020
#include "mozilla/dom/TrustedTypePolicyFactory.h"
21+
#include "mozilla/dom/TrustedTypesConstants.h"
2122
#include "nsGlobalWindowInner.h"
2223
#include "nsLiteralString.h"
2324
#include "nsTArray.h"
@@ -248,6 +249,10 @@ MOZ_CAN_RUN_SCRIPT inline const nsAString* GetTrustedTypesCompliantString(
248249
TrustedScriptOrNullIsEmptyString>) {
249250
return aInput.IsNullIsEmptyString();
250251
}
252+
if constexpr (std::is_same_v<TrustedTypeOrStringArg, const nsAString*>) {
253+
Unused << aInput;
254+
return true;
255+
}
251256
MOZ_ASSERT_UNREACHABLE();
252257
return false;
253258
};
@@ -265,6 +270,9 @@ MOZ_CAN_RUN_SCRIPT inline const nsAString* GetTrustedTypesCompliantString(
265270
TrustedScriptOrNullIsEmptyString>) {
266271
return &aInput.GetAsNullIsEmptyString();
267272
}
273+
if constexpr (std::is_same_v<TrustedTypeOrStringArg, const nsAString*>) {
274+
return aInput;
275+
}
268276
MOZ_ASSERT_UNREACHABLE();
269277
return static_cast<const nsAString*>(&EmptyString());
270278
};
@@ -284,6 +292,10 @@ MOZ_CAN_RUN_SCRIPT inline const nsAString* GetTrustedTypesCompliantString(
284292
TrustedScriptURLOrString>) {
285293
return aInput.IsTrustedScriptURL();
286294
}
295+
if constexpr (std::is_same_v<TrustedTypeOrStringArg, const nsAString*>) {
296+
Unused << aInput;
297+
return false;
298+
}
287299
MOZ_ASSERT_UNREACHABLE();
288300
return false;
289301
};
@@ -303,6 +315,7 @@ MOZ_CAN_RUN_SCRIPT inline const nsAString* GetTrustedTypesCompliantString(
303315
TrustedScriptURLOrString>) {
304316
return &aInput.GetAsTrustedScriptURL().mData;
305317
}
318+
Unused << aInput;
306319
MOZ_ASSERT_UNREACHABLE();
307320
return &EmptyString();
308321
};
@@ -408,13 +421,15 @@ bool GetTrustedTypeDataForAttribute(const nsAtom* aElementName,
408421
if (aAttributeNamespaceID == kNameSpaceID_None &&
409422
aAttributeName == nsGkAtoms::srcdoc) {
410423
aTrustedType = TrustedType::TrustedHTML;
424+
aSink.AssignLiteral(u"HTMLIFrameElement srcdoc");
411425
return true;
412426
}
413427
} else if (aElementName == nsGkAtoms::script) {
414428
// HTMLScriptElement
415429
if (aAttributeNamespaceID == kNameSpaceID_None &&
416430
aAttributeName == nsGkAtoms::src) {
417431
aTrustedType = TrustedType::TrustedScriptURL;
432+
aSink.AssignLiteral(u"HTMLScriptElement src");
418433
return true;
419434
}
420435
}
@@ -425,6 +440,7 @@ bool GetTrustedTypeDataForAttribute(const nsAtom* aElementName,
425440
aAttributeNamespaceID == kNameSpaceID_XLink) &&
426441
aAttributeName == nsGkAtoms::href) {
427442
aTrustedType = TrustedType::TrustedScriptURL;
443+
aSink.AssignLiteral(u"SVGScriptElement href");
428444
return true;
429445
}
430446
}
@@ -433,4 +449,73 @@ bool GetTrustedTypeDataForAttribute(const nsAtom* aElementName,
433449
return false;
434450
}
435451

452+
MOZ_CAN_RUN_SCRIPT const nsAString* GetTrustedTypesCompliantAttributeValue(
453+
const nsINode& aElement, nsAtom* aAttributeName,
454+
int32_t aAttributeNamespaceID,
455+
const TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString& aNewValue,
456+
Maybe<nsAutoString>& aResultHolder, ErrorResult& aError) {
457+
auto getAsTrustedType = [&aNewValue] {
458+
if (aNewValue.IsTrustedHTML()) {
459+
return &aNewValue.GetAsTrustedHTML().mData;
460+
}
461+
if (aNewValue.IsTrustedScript()) {
462+
return &aNewValue.GetAsTrustedScript().mData;
463+
}
464+
MOZ_ASSERT(aNewValue.IsTrustedScriptURL());
465+
return &aNewValue.GetAsTrustedScriptURL().mData;
466+
};
467+
auto getContent = [&aNewValue, &getAsTrustedType] {
468+
return aNewValue.IsString() ? &aNewValue.GetAsString() : getAsTrustedType();
469+
};
470+
471+
if (!StaticPrefs::dom_security_trusted_types_enabled()) {
472+
// A trusted type might've been created before the pref was set to `false`,
473+
// so we cannot assume aNewValue.IsString().
474+
return getContent();
475+
}
476+
477+
// In the common situation of non-data document without any
478+
// require-trusted-types-for directive, we just return immediately.
479+
const NodeInfo* nodeInfo = aElement.NodeInfo();
480+
Document* ownerDoc = nodeInfo->GetDocument();
481+
const bool ownerDocLoadedAsData = ownerDoc->IsLoadedAsData();
482+
if (!ownerDoc->HasPolicyWithRequireTrustedTypesForDirective() &&
483+
!ownerDocLoadedAsData) {
484+
return getContent();
485+
}
486+
487+
TrustedType expectedType;
488+
nsAutoString sink;
489+
if (!GetTrustedTypeDataForAttribute(
490+
nodeInfo->NameAtom(), nodeInfo->NamespaceID(), aAttributeName,
491+
aAttributeNamespaceID, expectedType, sink)) {
492+
return getContent();
493+
}
494+
495+
if ((expectedType == TrustedType::TrustedHTML && aNewValue.IsTrustedHTML()) ||
496+
(expectedType == TrustedType::TrustedScript &&
497+
aNewValue.IsTrustedScript()) ||
498+
(expectedType == TrustedType::TrustedScriptURL &&
499+
aNewValue.IsTrustedScriptURL())) {
500+
return getAsTrustedType();
501+
}
502+
503+
const nsAString* input =
504+
aNewValue.IsString() ? &aNewValue.GetAsString() : getAsTrustedType();
505+
switch (expectedType) {
506+
case TrustedType::TrustedHTML:
507+
return GetTrustedTypesCompliantString<TrustedHTML>(
508+
input, sink, kTrustedTypesOnlySinkGroup, aElement, aResultHolder,
509+
aError);
510+
case TrustedType::TrustedScript:
511+
return GetTrustedTypesCompliantString<TrustedScript>(
512+
input, sink, kTrustedTypesOnlySinkGroup, aElement, aResultHolder,
513+
aError);
514+
case TrustedType::TrustedScriptURL:
515+
return GetTrustedTypesCompliantString<TrustedScriptURL>(
516+
input, sink, kTrustedTypesOnlySinkGroup, aElement, aResultHolder,
517+
aError);
518+
}
519+
}
520+
436521
} // namespace mozilla::dom::TrustedTypeUtils

dom/security/trusted-types/TrustedTypeUtils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class TrustedScriptOrString;
3333
class TrustedScriptOrNullIsEmptyString;
3434
class TrustedScriptURL;
3535
class TrustedScriptURLOrString;
36+
class TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString;
3637

3738
namespace TrustedTypeUtils {
3839

@@ -97,6 +98,13 @@ bool GetTrustedTypeDataForAttribute(const nsAtom* aElementName,
9798
TrustedType& aTrustedType,
9899
nsAString& aSink);
99100

101+
// https://w3c.github.io/trusted-types/dist/spec/#abstract-opdef-get-trusted-types-compliant-attribute-value
102+
MOZ_CAN_RUN_SCRIPT const nsAString* GetTrustedTypesCompliantAttributeValue(
103+
const nsINode& aElement, nsAtom* aAttributeName,
104+
int32_t aAttributeNamespaceID,
105+
const TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString& aNewValue,
106+
Maybe<nsAutoString>& aResultHolder, ErrorResult& aError);
107+
100108
} // namespace TrustedTypeUtils
101109

102110
} // namespace dom

dom/webidl/Element.webidl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ interface Element : Node {
5050
[CEReactions, NeedsSubjectPrincipal=NonSystem, Throws]
5151
boolean toggleAttribute(DOMString name, optional boolean force);
5252
[CEReactions, NeedsSubjectPrincipal=NonSystem, Throws]
53-
undefined setAttribute(DOMString name, DOMString value);
53+
undefined setAttribute(DOMString name, (TrustedType or DOMString) value);
5454
[CEReactions, NeedsSubjectPrincipal=NonSystem, Throws]
55-
undefined setAttributeNS(DOMString? namespace, DOMString name, DOMString value);
55+
undefined setAttributeNS(DOMString? namespace, DOMString name, (TrustedType or DOMString) value);
5656
[CEReactions, Throws]
5757
undefined removeAttribute(DOMString name);
5858
[CEReactions, Throws]
@@ -417,3 +417,6 @@ partial interface Element {
417417
[Pref="dom.webcomponents.shadowdom.declarative.enabled"]
418418
DOMString getHTML(optional GetHTMLOptions options = {});
419419
};
420+
421+
// https://w3c.github.io/trusted-types/dist/spec/#integrations
422+
typedef (TrustedHTML or TrustedScript or TrustedScriptURL) TrustedType;

testing/web-platform/meta/trusted-types/GlobalEventHandlers-onclick.html.ini

Lines changed: 0 additions & 6 deletions
This file was deleted.

testing/web-platform/meta/trusted-types/TrustedTypePolicyFactory-metadata.tentative.html.ini

Lines changed: 0 additions & 36 deletions
This file was deleted.
Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,3 @@
11
[block-string-assignment-to-Element-setAttribute.html]
2-
[script.src accepts only TrustedScriptURL]
3-
expected: FAIL
4-
5-
[iframe.srcdoc accepts only TrustedHTML]
6-
expected: FAIL
7-
8-
[div.onclick accepts only TrustedScript]
9-
expected: FAIL
10-
11-
[`Script.prototype.setAttribute.SrC = string` throws.]
12-
expected: FAIL
13-
14-
[script.src's mutationobservers receive the default policy's value.]
15-
expected: FAIL
16-
17-
[iframe.srcdoc's mutationobservers receive the default policy's value.]
18-
expected: FAIL
19-
20-
[div.onclick's mutationobservers receive the default policy's value.]
21-
expected: FAIL
22-
23-
[div.onclick accepts string and null after default policy was created.]
24-
expected: FAIL
25-
262
[`script.src = setAttributeNode(embed.src)` with string works.]
273
expected: FAIL

testing/web-platform/meta/trusted-types/block-string-assignment-to-Element-setAttributeNS.html.ini

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
 (0)