Skip to content

Commit ef2e647

Browse files
committed
1 parent 5c9ac1e commit ef2e647

11 files changed

+203
-396
lines changed

dom/base/Element.cpp

+74
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

+17
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

+87
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"
@@ -250,6 +251,10 @@ MOZ_CAN_RUN_SCRIPT inline const nsAString* GetTrustedTypesCompliantString(
250251
TrustedScriptOrNullIsEmptyString>) {
251252
return aInput.IsNullIsEmptyString();
252253
}
254+
if constexpr (std::is_same_v<TrustedTypeOrStringArg, const nsAString*>) {
255+
Unused << aInput;
256+
return true;
257+
}
253258
MOZ_ASSERT_UNREACHABLE();
254259
return false;
255260
};
@@ -267,6 +272,9 @@ MOZ_CAN_RUN_SCRIPT inline const nsAString* GetTrustedTypesCompliantString(
267272
TrustedScriptOrNullIsEmptyString>) {
268273
return &aInput.GetAsNullIsEmptyString();
269274
}
275+
if constexpr (std::is_same_v<TrustedTypeOrStringArg, const nsAString*>) {
276+
return aInput;
277+
}
270278
MOZ_ASSERT_UNREACHABLE();
271279
return static_cast<const nsAString*>(&EmptyString());
272280
};
@@ -286,6 +294,10 @@ MOZ_CAN_RUN_SCRIPT inline const nsAString* GetTrustedTypesCompliantString(
286294
TrustedScriptURLOrString>) {
287295
return aInput.IsTrustedScriptURL();
288296
}
297+
if constexpr (std::is_same_v<TrustedTypeOrStringArg, const nsAString*>) {
298+
Unused << aInput;
299+
return false;
300+
}
289301
MOZ_ASSERT_UNREACHABLE();
290302
return false;
291303
};
@@ -305,6 +317,7 @@ MOZ_CAN_RUN_SCRIPT inline const nsAString* GetTrustedTypesCompliantString(
305317
TrustedScriptURLOrString>) {
306318
return &aInput.GetAsTrustedScriptURL().mData;
307319
}
320+
Unused << aInput;
308321
MOZ_ASSERT_UNREACHABLE();
309322
return &EmptyString();
310323
};
@@ -410,13 +423,15 @@ bool GetTrustedTypeDataForAttribute(const nsAtom* aElementName,
410423
if (aAttributeNamespaceID == kNameSpaceID_None &&
411424
aAttributeName == nsGkAtoms::srcdoc) {
412425
aTrustedType = TrustedType::TrustedHTML;
426+
aSink.AssignLiteral(u"HTMLIFrameElement srcdoc");
413427
return true;
414428
}
415429
} else if (aElementName == nsGkAtoms::script) {
416430
// HTMLScriptElement
417431
if (aAttributeNamespaceID == kNameSpaceID_None &&
418432
aAttributeName == nsGkAtoms::src) {
419433
aTrustedType = TrustedType::TrustedScriptURL;
434+
aSink.AssignLiteral(u"HTMLScriptElement src");
420435
return true;
421436
}
422437
}
@@ -427,6 +442,7 @@ bool GetTrustedTypeDataForAttribute(const nsAtom* aElementName,
427442
aAttributeNamespaceID == kNameSpaceID_XLink) &&
428443
aAttributeName == nsGkAtoms::href) {
429444
aTrustedType = TrustedType::TrustedScriptURL;
445+
aSink.AssignLiteral(u"SVGScriptElement href");
430446
return true;
431447
}
432448
}
@@ -435,4 +451,75 @@ bool GetTrustedTypeDataForAttribute(const nsAtom* aElementName,
435451
return false;
436452
}
437453

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

dom/security/trusted-types/TrustedTypeUtils.h

+8
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

+5-2
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

-6
This file was deleted.

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

-36
This file was deleted.
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

-3
This file was deleted.

0 commit comments

Comments
 (0)