Skip to content
Permalink
Browse files
PCM: Add high entropy attributionSourceNonce attribute to anchor tags
https://bugs.webkit.org/show_bug.cgi?id=221934
<rdar://73581230>

Reviewed by Jiewen Tan.

In Private Click Measurement (PCM), the source site should have the option to
provide a high entropy nonce with which PCM can asynchronously validate its
subsequent, asynchronous request for a signature of its unlinkable token.

The nonce attribute's name is attributionSourceNonce and it's a
128-bit/16-byte Base64URL encoded string.

The attribute is behind the experimental feature flag
PrivateClickMeasurementFraudPrevention.

Source/WebCore:

New API tests added.

* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::parsePrivateClickMeasurement const):
* html/HTMLAnchorElement.idl:
* html/HTMLAttributeNames.in:
* loader/PrivateClickMeasurement.h:
(WebCore::PrivateClickMeasurement::EphemeralSourceNonce::EphemeralSourceNonce):
(WebCore::PrivateClickMeasurement::EphemeralSourceNonce::isValid const):
(WebCore::PrivateClickMeasurement::setEphemeralSourceNonce):
(WebCore::PrivateClickMeasurement::ephemeralSourceNonce const):
(WebCore::PrivateClickMeasurement::clearEphemeralSourceNonce):
* page/Settings.yaml:

Tools:

* TestWebKitAPI/Tests/WebCore/PrivateClickMeasurement.cpp:
(TestWebKitAPI::TEST):


Canonical link: https://commits.webkit.org/234127@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@272894 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
johnwilander committed Feb 16, 2021
1 parent 336a023 commit cc94b9412ed0dbccd33464000a264fd7987c881f
Showing 8 changed files with 126 additions and 1 deletion.
@@ -1,3 +1,35 @@
2021-02-15 John Wilander <wilander@apple.com>

PCM: Add high entropy attributionSourceNonce attribute to anchor tags
https://bugs.webkit.org/show_bug.cgi?id=221934
<rdar://73581230>

Reviewed by Jiewen Tan.

In Private Click Measurement (PCM), the source site should have the option to
provide a high entropy nonce with which PCM can asynchronously validate its
subsequent, asynchronous request for a signature of its unlinkable token.

The nonce attribute's name is attributionSourceNonce and it's a
128-bit/16-byte Base64URL encoded string.

The attribute is behind the experimental feature flag
PrivateClickMeasurementFraudPrevention.

New API tests added.

* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::parsePrivateClickMeasurement const):
* html/HTMLAnchorElement.idl:
* html/HTMLAttributeNames.in:
* loader/PrivateClickMeasurement.h:
(WebCore::PrivateClickMeasurement::EphemeralSourceNonce::EphemeralSourceNonce):
(WebCore::PrivateClickMeasurement::EphemeralSourceNonce::isValid const):
(WebCore::PrivateClickMeasurement::setEphemeralSourceNonce):
(WebCore::PrivateClickMeasurement::ephemeralSourceNonce const):
(WebCore::PrivateClickMeasurement::clearEphemeralSourceNonce):
* page/Settings.yaml:

2021-02-15 Eric Carlson <eric.carlson@apple.com>

[macOS] Connect Touch Bar to MediaSession
@@ -450,7 +450,19 @@ Optional<PrivateClickMeasurement> HTMLAnchorElement::parsePrivateClickMeasuremen
return WTF::nullopt;
}

return PrivateClickMeasurement { SourceID(attributionSourceID.value()), SourceSite(documentRegistrableDomain), AttributeOnSite(attributeOnURL) };
auto privateClickMeasurement = PrivateClickMeasurement { SourceID(attributionSourceID.value()), SourceSite(documentRegistrableDomain), AttributeOnSite(attributeOnURL) };

auto attributionSourceNonceAttr = attributeWithoutSynchronization(attributionsourcenonceAttr);
if (!attributionSourceNonceAttr.isEmpty()) {
auto ephemeralNonce = PrivateClickMeasurement::EphemeralSourceNonce { attributionSourceNonceAttr };
if (!ephemeralNonce.isValid()) {
document().addConsoleMessage(MessageSource::Other, MessageLevel::Warning, "attributionsourcenonce was not valid."_s);
return WTF::nullopt;
}
privateClickMeasurement.setEphemeralSourceNonce(WTFMove(ephemeralNonce));
}

return privateClickMeasurement;
}

void HTMLAnchorElement::handleClick(Event& event)
@@ -23,6 +23,7 @@
] interface HTMLAnchorElement : HTMLElement {
[CEReactions=NotNeeded, EnabledBySetting=PrivateClickMeasurement, Reflect] attribute DOMString attributionsourceid;
[CEReactions=NotNeeded, EnabledBySetting=PrivateClickMeasurement, Reflect] attribute DOMString attributeon;
[CEReactions=NotNeeded, EnabledBySetting=PrivateClickMeasurementFraudPrevention, Reflect] attribute DOMString attributionsourcenonce;
[CEReactions=NotNeeded, Reflect] attribute DOMString charset;
[CEReactions=NotNeeded, Reflect] attribute DOMString coords;
[CEReactions=NotNeeded, Conditional=DOWNLOAD_ATTRIBUTE, EnabledBySetting=DownloadAttribute, Reflect] attribute DOMString download;
@@ -69,6 +69,7 @@ aria-valuetext
as
async
attributionsourceid
attributionsourcenonce
attributeon
autocomplete
autofocus
@@ -32,6 +32,7 @@
#include <wtf/Optional.h>
#include <wtf/URL.h>
#include <wtf/WallTime.h>
#include <wtf/text/Base64.h>
#include <wtf/text/StringHash.h>
#include <wtf/text/WTFString.h>

@@ -200,6 +201,28 @@ class PrivateClickMeasurement {
static const bool safeToCompareToEmptyOrDeleted = false;
};

struct EphemeralSourceNonce {
static constexpr uint32_t RequiredNumberOfBytes = 16;

EphemeralSourceNonce() = default;
explicit EphemeralSourceNonce(const String& nonceString)
: nonce { nonceString }
{
}

// FIXME: Investigate if we can do with a simple length check instead of decoding.
// https://bugs.webkit.org/show_bug.cgi?id=221945
bool isValid() const
{
Vector<uint8_t> digest;
if (!base64URLDecode(nonce, digest))
return false;
return digest.size() == RequiredNumberOfBytes;
}

String nonce;
};

struct Priority {
static constexpr uint32_t MaxEntropy = 63;

@@ -255,6 +278,9 @@ class PrivateClickMeasurement {
WEBCORE_EXPORT Ref<JSON::Object> json() const;
const SourceSite& sourceSite() const { return m_sourceSite; };
const AttributeOnSite& attributeOnSite() const { return m_attributeOnSite; };
void setEphemeralSourceNonce(EphemeralSourceNonce&& nonce) { m_ephemeralSourceNonce = WTFMove(nonce); };
Optional<EphemeralSourceNonce> ephemeralSourceNonce() const { return !m_ephemeralSourceNonce ? WTF::nullopt : m_ephemeralSourceNonce->isValid() ? m_ephemeralSourceNonce : WTF::nullopt; };
void clearEphemeralSourceNonce() { m_ephemeralSourceNonce = WTF::nullopt; };
WallTime timeOfAdClick() const { return m_timeOfAdClick; }
Optional<WallTime> earliestTimeToSend() const { return m_earliestTimeToSend; };
void setEarliestTimeToSend(WallTime time) { m_earliestTimeToSend = time; }
@@ -278,6 +304,7 @@ class PrivateClickMeasurement {
String m_purchaser;
WallTime m_timeOfAdClick;

Optional<EphemeralSourceNonce> m_ephemeralSourceNonce;
Optional<AttributionTriggerData> m_attributionTriggerData;
Optional<WallTime> m_earliestTimeToSend;
};
@@ -437,6 +437,12 @@ PreventKeyboardDOMEventDispatch:
WebCore:
default: false

PrivateClickMeasurementFraudPreventionEnabled:
type: bool
defaultValue:
WebCore:
default: false

QuickTimePluginReplacementEnabled:
type: bool
defaultValue:
@@ -1,3 +1,24 @@
2021-02-15 John Wilander <wilander@apple.com>

PCM: Add high entropy attributionSourceNonce attribute to anchor tags
https://bugs.webkit.org/show_bug.cgi?id=221934
<rdar://73581230>

Reviewed by Jiewen Tan.

In Private Click Measurement (PCM), the source site should have the option to
provide a high entropy nonce with which PCM can asynchronously validate its
subsequent, asynchronous request for a signature of its unlinkable token.

The nonce attribute's name is attributionSourceNonce and it's a
128-bit/16-byte Base64URL encoded string.

The attribute is behind the experimental feature flag
PrivateClickMeasurementFraudPrevention.

* TestWebKitAPI/Tests/WebCore/PrivateClickMeasurement.cpp:
(TestWebKitAPI::TEST):

2021-02-15 Aakash Jain <aakash_jain@apple.com>

[ews] Add python 3 support - part 2
@@ -123,6 +123,12 @@ TEST(PrivateClickMeasurement, ValidConversionURLs)
ASSERT_EQ(optionalConversion->priority, (uint32_t)2);
}

TEST(PrivateClickMeasurement, ValidSourceNonce)
{
auto ephemeralNonce = PrivateClickMeasurement::EphemeralSourceNonce { "ABCDEFabcdef0123456789"_s };
ASSERT_TRUE(ephemeralNonce.isValid());
}

// Negative test cases.

TEST(PrivateClickMeasurement, InvalidSourceID)
@@ -275,4 +281,23 @@ TEST(PrivateClickMeasurement, InvalidConversionWithDisallowedURLComponents)
ASSERT_FALSE(optionalConversion);
}

TEST(PrivateClickMeasurement, InvalidSourceNonce)
{
// Fewer than the requried number of bytes.
auto ephemeralNonce = PrivateClickMeasurement::EphemeralSourceNonce { "ABCDabcd0123456789"_s };
ASSERT_FALSE(ephemeralNonce.isValid());
// More than the requried number of bytes.
ephemeralNonce = PrivateClickMeasurement::EphemeralSourceNonce { "ABCDEFGHIabcdefghi0123456789"_s };
ASSERT_FALSE(ephemeralNonce.isValid());
// Illegal, ASCII character '/'.
ephemeralNonce = PrivateClickMeasurement::EphemeralSourceNonce { "ABCDEFabcde/0123456789"_s };
ASSERT_FALSE(ephemeralNonce.isValid());
// Illegal, non-ASCII character 'å'.
ephemeralNonce = PrivateClickMeasurement::EphemeralSourceNonce { "ABCDEFabcdeå0123456789" };
ASSERT_FALSE(ephemeralNonce.isValid());
// Empty string.
ephemeralNonce = PrivateClickMeasurement::EphemeralSourceNonce { StringImpl::empty() };
ASSERT_FALSE(ephemeralNonce.isValid());
}

} // namespace TestWebKitAPI

0 comments on commit cc94b94

Please sign in to comment.