diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index f77a8f1453d0..a7229fe41264 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -21,6 +21,7 @@ #include "nsIClassOfService.h" #include "nsIHttpProtocolHandler.h" #include "nsIContentPolicy.h" +#include "nsIPrivateAttributionService.h" #include "nsContentPolicyUtils.h" #include "nsISupportsPriority.h" #include "nsIWebProtocolHandlerRegistrar.h" @@ -41,11 +42,13 @@ #include "BatteryManager.h" #include "mozilla/dom/CredentialsContainer.h" #include "mozilla/dom/Clipboard.h" +#include "mozilla/dom/ContentChild.h" #include "mozilla/dom/FeaturePolicyUtils.h" #include "mozilla/dom/GamepadServiceTest.h" #include "mozilla/dom/MediaCapabilities.h" #include "mozilla/dom/MediaSession.h" #include "mozilla/dom/power/PowerManagerService.h" +#include "mozilla/dom/PrivateAttribution.h" #include "mozilla/dom/LockManager.h" #include "mozilla/dom/MIDIAccessManager.h" #include "mozilla/dom/MIDIOptionsBinding.h" @@ -161,6 +164,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAddonManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWebGpu) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocks) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrivateAttribution) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUserActivation) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWakeLock) @@ -250,6 +254,8 @@ void Navigator::Invalidate() { mLocks = nullptr; } + mPrivateAttribution = nullptr; + mUserActivation = nullptr; mSharePromise = nullptr; @@ -2273,6 +2279,13 @@ dom::LockManager* Navigator::Locks() { return mLocks; } +dom::PrivateAttribution* Navigator::PrivateAttribution() { + if (!mPrivateAttribution) { + mPrivateAttribution = new dom::PrivateAttribution(GetWindow()->AsGlobal()); + } + return mPrivateAttribution; +} + /* static */ bool Navigator::Webdriver() { #ifdef ENABLE_WEBDRIVER diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index c29455bb2957..4c400554f9b1 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -42,6 +42,7 @@ class ServiceWorkerContainer; class CredentialsContainer; class Clipboard; class LockManager; +class PrivateAttribution; class HTMLMediaElement; class AudioContext; class WakeLockJS; @@ -209,6 +210,7 @@ class Navigator final : public nsISupports, public nsWrapperCache { dom::Clipboard* Clipboard(); webgpu::Instance* Gpu(); dom::LockManager* Locks(); + dom::PrivateAttribution* PrivateAttribution(); static bool Webdriver(); @@ -300,7 +302,8 @@ class Navigator final : public nsISupports, public nsWrapperCache { RefPtr mAddonManager; RefPtr mWebGpu; RefPtr mSharePromise; // Web Share API related - RefPtr mLocks; + RefPtr mLocks; + RefPtr mPrivateAttribution; RefPtr mUserActivation; RefPtr mWakeLock; }; diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 6e72098459be..59bee0676a6f 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -17,9 +17,11 @@ #include "chrome/common/process_watcher.h" #include "mozilla/Result.h" +#include "mozilla/Services.h" #include "mozilla/XREAppData.h" #include "nsComponentManagerUtils.h" #include "nsIBrowserDOMWindow.h" +#include "nsIPrivateAttributionService.h" #include "GMPServiceParent.h" #include "HandlerServiceParent.h" @@ -1244,6 +1246,35 @@ mozilla::ipc::IPCResult ContentParent::RecvCreateGMPService() { return IPC_OK(); } +IPCResult ContentParent::RecvAttributionEvent( + const nsACString& aHost, PrivateAttributionImpressionType aType, + uint32_t aIndex, const nsAString& aAd, const nsACString& aTargetHost) { + nsCOMPtr pa = + components::PrivateAttribution::Service(); + if (NS_WARN_IF(!pa)) { + return IPC_OK(); + } + pa->OnAttributionEvent(aHost, GetEnumString(aType), aIndex, aAd, aTargetHost); + return IPC_OK(); +} + +IPCResult ContentParent::RecvAttributionConversion( + const nsACString& aHost, const nsAString& aTask, uint32_t aHistogramSize, + const Maybe& aLoopbackDays, + const Maybe& aImpressionType, + const nsTArray& aAds, const nsTArray& aSourceHosts) { + nsCOMPtr pa = + components::PrivateAttribution::Service(); + if (NS_WARN_IF(!pa)) { + return IPC_OK(); + } + pa->OnAttributionConversion( + aHost, aTask, aHistogramSize, aLoopbackDays.valueOr(0), + aImpressionType ? GetEnumString(*aImpressionType) : EmptyCString(), aAds, + aSourceHosts); + return IPC_OK(); +} + Atomic sContentParentTelemetryEventEnabled(false); /*static*/ diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index e0e24cd9db14..25804538584b 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -443,6 +443,15 @@ class ContentParent final : public PContentParent, return PContentParent::RecvPHalConstructor(aActor); } + mozilla::ipc::IPCResult RecvAttributionEvent( + const nsACString& aHost, PrivateAttributionImpressionType aType, + uint32_t aIndex, const nsAString& aAd, const nsACString& aTargetHost); + mozilla::ipc::IPCResult RecvAttributionConversion( + const nsACString& aHost, const nsAString& aTask, uint32_t aHistogramSize, + const Maybe& aLoopbackDays, + const Maybe& aImpressionType, + const nsTArray& aAds, const nsTArray& aSourceHosts); + PHeapSnapshotTempFileHelperParent* AllocPHeapSnapshotTempFileHelperParent(); PRemoteSpellcheckEngineParent* AllocPRemoteSpellcheckEngineParent(); diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index e8509345367b..238663ad746c 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -160,6 +160,7 @@ using mozilla::PerfStats::MetricMask from "mozilla/PerfStats.h"; [RefCounted] using class nsIX509Cert from "nsIX509Cert.h"; using nsIDNSService::ResolverMode from "nsIDNSService.h"; using mozilla::dom::UserActivation::Modifiers from "mozilla/dom/UserActivation.h"; +using mozilla::dom::PrivateAttributionImpressionType from "mozilla/dom/PrivateAttributionIPCUtils.h"; union ChromeRegistryItem { @@ -1970,6 +1971,17 @@ parent: // test document before taking the snapshot and starting e.g. IPC fuzzing. async SignalFuzzingReady(); #endif + + async AttributionEvent(nsCString aSourceHost, + PrivateAttributionImpressionType aType, + uint32_t aIndex, nsString aAd, nsCString aTargetHost); + + async AttributionConversion(nsCString aSourceHost, nsString aTask, + uint32_t aHistogramSize, + uint32_t? aLoopbackDays, + PrivateAttributionImpressionType? aImpressionType, + nsString[] aAds, + nsCString[] aImpressionSourceHosts); }; } diff --git a/dom/moz.build b/dom/moz.build index f781bd370839..88fc49cb7365 100644 --- a/dom/moz.build +++ b/dom/moz.build @@ -74,6 +74,7 @@ DIRS += [ "audiochannel", "broadcastchannel", "messagechannel", + "privateattribution", "promise", "smil", "streams", diff --git a/dom/origin-trials/OriginTrials.cpp b/dom/origin-trials/OriginTrials.cpp index 9f9e6b44fee0..0bb61de354e0 100644 --- a/dom/origin-trials/OriginTrials.cpp +++ b/dom/origin-trials/OriginTrials.cpp @@ -212,6 +212,8 @@ static int32_t PrefState(OriginTrial aTrial) { return StaticPrefs::dom_origin_trials_test_trial_state(); case OriginTrial::CoepCredentialless: return StaticPrefs::dom_origin_trials_coep_credentialless_state(); + case OriginTrial::PrivateAttribution: + return StaticPrefs::dom_origin_trials_private_attribution_state(); case OriginTrial::MAX: MOZ_ASSERT_UNREACHABLE("Unknown trial!"); break; diff --git a/dom/origin-trials/ffi/lib.rs b/dom/origin-trials/ffi/lib.rs index 1745c9e790a6..81b408d96a62 100644 --- a/dom/origin-trials/ffi/lib.rs +++ b/dom/origin-trials/ffi/lib.rs @@ -10,6 +10,7 @@ pub enum OriginTrial { // NOTE(emilio): 0 is reserved for WebIDL usage. TestTrial = 1, CoepCredentialless = 2, + PrivateAttribution = 3, MAX, } @@ -19,6 +20,7 @@ impl OriginTrial { Some(match s { "TestTrial" => Self::TestTrial, "CoepCredentialless" => Self::CoepCredentialless, + "PrivateAttribution" => Self::PrivateAttribution, _ => return None, }) } diff --git a/dom/origin-trials/tests/mochitest/mochitest.toml b/dom/origin-trials/tests/mochitest/mochitest.toml index 1c7bedb697d3..9c3013221f5a 100644 --- a/dom/origin-trials/tests/mochitest/mochitest.toml +++ b/dom/origin-trials/tests/mochitest/mochitest.toml @@ -13,9 +13,11 @@ support-files = [ # verification fails, expectedly. skip-if = [ "!debug", - "xorigin", # AudioWorklet requires secure context + "xorigin", ] +# We want to test that trials are exposed in worklets, and AudioWorklet +# requires secure context. scheme = "https" ["test_expired_token.html"] diff --git a/dom/origin-trials/tests/mochitest/test_meta_simple.html b/dom/origin-trials/tests/mochitest/test_meta_simple.html index 8b853a8774f3..e63d34575d30 100644 --- a/dom/origin-trials/tests/mochitest/test_meta_simple.html +++ b/dom/origin-trials/tests/mochitest/test_meta_simple.html @@ -3,11 +3,15 @@ + + diff --git a/dom/origin-trials/tests/mochitest/test_trial_hidden.html b/dom/origin-trials/tests/mochitest/test_trial_hidden.html index 90f7f8da0ac9..a35ffc081ec8 100644 --- a/dom/origin-trials/tests/mochitest/test_trial_hidden.html +++ b/dom/origin-trials/tests/mochitest/test_trial_hidden.html @@ -3,4 +3,8 @@ diff --git a/dom/privateattribution/PrivateAttribution.cpp b/dom/privateattribution/PrivateAttribution.cpp new file mode 100644 index 000000000000..08c00f0a7e75 --- /dev/null +++ b/dom/privateattribution/PrivateAttribution.cpp @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "PrivateAttribution.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/PrivateAttributionBinding.h" +#include "mozilla/Components.h" +#include "nsIGlobalObject.h" +#include "nsIPrivateAttributionService.h" +#include "nsXULAppAPI.h" +#include "nsURLHelper.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PrivateAttribution, mOwner) + +PrivateAttribution::PrivateAttribution(nsIGlobalObject* aGlobal) + : mOwner(aGlobal) { + MOZ_ASSERT(aGlobal); +} + +JSObject* PrivateAttribution::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return PrivateAttribution_Binding::Wrap(aCx, this, aGivenProto); +} + +PrivateAttribution::~PrivateAttribution() = default; + +bool PrivateAttribution::GetSourceHost(nsACString& aSourceHost, + ErrorResult& aRv) { + MOZ_ASSERT(mOwner); + nsIPrincipal* prin = mOwner->PrincipalOrNull(); + if (!prin || NS_FAILED(prin->GetHost(aSourceHost))) { + aRv.ThrowInvalidStateError("Couldn't get source host"); + return false; + } + return true; +} + +[[nodiscard]] static bool ValidateHost(const nsACString& aHost, + ErrorResult& aRv) { + if (!net_IsValidHostName(aHost)) { + aRv.ThrowSyntaxError(aHost + " is not a valid host name"_ns); + return false; + } + return true; +} + +void PrivateAttribution::SaveImpression( + const PrivateAttributionImpressionOptions& aOptions, ErrorResult& aRv) { + nsAutoCString source; + if (!GetSourceHost(source, aRv)) { + return; + } + + if (!ValidateHost(aOptions.mTarget, aRv)) { + return; + } + + if (XRE_IsParentProcess()) { + nsCOMPtr pa = + components::PrivateAttribution::Service(); + if (NS_WARN_IF(!pa)) { + return; + } + pa->OnAttributionEvent(source, GetEnumString(aOptions.mType), + aOptions.mIndex, aOptions.mAd, aOptions.mTarget); + return; + } + + auto* content = ContentChild::GetSingleton(); + if (NS_WARN_IF(!content)) { + return; + } + content->SendAttributionEvent(source, aOptions.mType, aOptions.mIndex, + aOptions.mAd, aOptions.mTarget); +} + +void PrivateAttribution::MeasureConversion( + const PrivateAttributionConversionOptions& aOptions, ErrorResult& aRv) { + nsAutoCString source; + if (!GetSourceHost(source, aRv)) { + return; + } + for (const nsACString& host : aOptions.mSources) { + if (!ValidateHost(host, aRv)) { + return; + } + } + if (XRE_IsParentProcess()) { + nsCOMPtr pa = + components::PrivateAttribution::Service(); + if (NS_WARN_IF(!pa)) { + return; + } + pa->OnAttributionConversion( + source, aOptions.mTask, aOptions.mHistogramSize, + aOptions.mLookbackDays.WasPassed() ? aOptions.mLookbackDays.Value() : 0, + aOptions.mImpression.WasPassed() + ? GetEnumString(aOptions.mImpression.Value()) + : EmptyCString(), + aOptions.mAds, aOptions.mSources); + return; + } + + auto* content = ContentChild::GetSingleton(); + if (NS_WARN_IF(!content)) { + return; + } + content->SendAttributionConversion( + source, aOptions.mTask, aOptions.mHistogramSize, + aOptions.mLookbackDays.WasPassed() ? Some(aOptions.mLookbackDays.Value()) + : Nothing(), + aOptions.mImpression.WasPassed() ? Some(aOptions.mImpression.Value()) + : Nothing(), + aOptions.mAds, aOptions.mSources); +} + +} // namespace mozilla::dom diff --git a/dom/privateattribution/PrivateAttribution.h b/dom/privateattribution/PrivateAttribution.h new file mode 100644 index 000000000000..244190d97e82 --- /dev/null +++ b/dom/privateattribution/PrivateAttribution.h @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_PrivateAttribution_h +#define mozilla_dom_PrivateAttribution_h + +#include "nsWrapperCache.h" +#include "nsCOMPtr.h" + +class nsIGlobalObject; +namespace mozilla { +class ErrorResult; +} + +namespace mozilla::dom { + +struct PrivateAttributionImpressionOptions; +struct PrivateAttributionConversionOptions; + +class PrivateAttribution final : public nsWrapperCache { + public: + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PrivateAttribution) + NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(PrivateAttribution) + + explicit PrivateAttribution(nsIGlobalObject* aGlobal); + static already_AddRefed Create(nsIGlobalObject& aGlobal); + + nsIGlobalObject* GetParentObject() const { return mOwner; } + JSObject* WrapObject(JSContext*, JS::Handle aGivenProto) override; + + void SaveImpression(const PrivateAttributionImpressionOptions&, ErrorResult&); + void MeasureConversion(const PrivateAttributionConversionOptions&, + ErrorResult&); + + private: + [[nodiscard]] bool GetSourceHost(nsACString&, ErrorResult&); + + ~PrivateAttribution(); + + nsCOMPtr mOwner; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_PrivateAttribution_h diff --git a/dom/privateattribution/PrivateAttributionIPCUtils.h b/dom/privateattribution/PrivateAttributionIPCUtils.h new file mode 100644 index 000000000000..6e79fc7b9723 --- /dev/null +++ b/dom/privateattribution/PrivateAttributionIPCUtils.h @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_PrivateAttributionIPCUtils_h +#define mozilla_dom_PrivateAttributionIPCUtils_h + +#include "mozilla/dom/PrivateAttributionBinding.h" +#include "mozilla/dom/BindingIPCUtils.h" + +namespace IPC { + +template <> +struct ParamTraits + : public mozilla::dom::WebIDLEnumSerializer< + mozilla::dom::PrivateAttributionImpressionType> {}; + +} // namespace IPC + +#endif diff --git a/dom/privateattribution/PrivateAttributionService.sys.mjs b/dom/privateattribution/PrivateAttributionService.sys.mjs new file mode 100644 index 000000000000..caf3cfdd8a43 --- /dev/null +++ b/dom/privateattribution/PrivateAttributionService.sys.mjs @@ -0,0 +1,31 @@ +/* vim: set ts=2 sw=2 sts=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * + */ +export class PrivateAttributionService { + onAttributionEvent(sourceHost, type, index, ad, targetHost) { + dump( + `onAttributionEvent(${sourceHost}, ${type}, ${index}, ${ad}, ${targetHost})\n` + ); + } + + onAttributionConversion( + sourceHost, + task, + histogramSize, + loopbackDays, + impressionType, + ads, + sourceHosts + ) { + dump( + `onAttributionConversion(${sourceHost}, ${task}, ${histogramSize}, ${loopbackDays}, ${impressionType}, ${ads}, ${sourceHosts})\n` + ); + } + + QueryInterface = ChromeUtils.generateQI([Ci.nsIPrivateAttributionService]); +} diff --git a/dom/privateattribution/components.conf b/dom/privateattribution/components.conf new file mode 100644 index 000000000000..6e1e7bcc4bd5 --- /dev/null +++ b/dom/privateattribution/components.conf @@ -0,0 +1,15 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Classes = [ + { + 'cid': '{57d16147-1deb-46ac-8f1c-1140b5e1ddfd}', + 'name': 'PrivateAttribution', + 'contract_ids': ['@mozilla.org/private-attribution;1'], + 'esModule': 'resource://gre/modules/PrivateAttributionService.sys.mjs', + 'constructor': 'PrivateAttributionService', + }, +] diff --git a/dom/privateattribution/moz.build b/dom/privateattribution/moz.build new file mode 100644 index 000000000000..f398d3915b60 --- /dev/null +++ b/dom/privateattribution/moz.build @@ -0,0 +1,35 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +with Files("**"): + BUG_COMPONENT = ("Core", "DOM: Core & HTML") + +EXPORTS.mozilla.dom += [ + "PrivateAttribution.h", + "PrivateAttributionIPCUtils.h", +] + +UNIFIED_SOURCES += [ + "PrivateAttribution.cpp", +] + +XPIDL_SOURCES += [ + "nsIPrivateAttributionService.idl", +] + +XPIDL_MODULE = "privateattribution" + +XPCOM_MANIFESTS += [ + "components.conf", +] + +EXTRA_JS_MODULES += [ + "PrivateAttributionService.sys.mjs", +] + +include("/ipc/chromium/chromium-config.mozbuild") + +FINAL_LIBRARY = "xul" diff --git a/dom/privateattribution/nsIPrivateAttributionService.idl b/dom/privateattribution/nsIPrivateAttributionService.idl new file mode 100644 index 000000000000..8401b54c9b45 --- /dev/null +++ b/dom/privateattribution/nsIPrivateAttributionService.idl @@ -0,0 +1,14 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +[scriptable, uuid(c7e7fc54-4133-4191-bd40-cc2b77fd21bc)] +interface nsIPrivateAttributionService : nsISupports +{ + void onAttributionEvent(in ACString sourceHost, in ACString type, in uint32_t index, in AString ad, in ACString targetHost); + void onAttributionConversion(in ACString sourceHost, in AString task, in uint32_t histogramSize, in uint32_t loopbackDays, in ACString impressionType, in Array ads, in Array sourceHosts); +}; diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index c7db0e5606bf..8638e94a17b0 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -394,3 +394,9 @@ partial interface Navigator { [SameObject, Pref="dom.screenwakelock.enabled"] readonly attribute WakeLock wakeLock; }; + +[SecureContext] +partial interface Navigator { + [SameObject, Trial="PrivateAttribution"] + readonly attribute PrivateAttribution privateAttribution; +}; diff --git a/dom/webidl/PrivateAttribution.webidl b/dom/webidl/PrivateAttribution.webidl new file mode 100644 index 000000000000..e6d4cf721115 --- /dev/null +++ b/dom/webidl/PrivateAttribution.webidl @@ -0,0 +1,29 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +enum PrivateAttributionImpressionType { "view", "click" }; + +dictionary PrivateAttributionImpressionOptions { + PrivateAttributionImpressionType type = "view"; + required unsigned long index; + required DOMString ad; + required UTF8String target; +}; + +dictionary PrivateAttributionConversionOptions { + required DOMString task; + required unsigned long histogramSize; + + unsigned long lookbackDays; + PrivateAttributionImpressionType impression; + sequence ads = []; + sequence sources = []; +}; + +[Trial="PrivateAttribution", SecureContext, Exposed=Window] +interface PrivateAttribution { + [Throws] undefined saveImpression(PrivateAttributionImpressionOptions options); + [Throws] undefined measureConversion(PrivateAttributionConversionOptions options); +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 58eb0ef8b613..96e9f6306493 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -804,6 +804,7 @@ WEBIDL_FILES = [ "PluginArray.webidl", "PointerEvent.webidl", "PopoverInvokerElement.webidl", + "PrivateAttribution.webidl", "ProcessingInstruction.webidl", "Promise.webidl", "PushEvent.webidl", diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 6ff399259c2e..453ef6e15894 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -3216,6 +3216,13 @@ value: 0 mirror: always +# Origin trial state for Private Attribution +# 0: normal, 1: always-enabled, 2: always-disabled +- name: dom.origin-trials.private-attribution.state + type: RelaxedAtomicInt32 + value: 0 + mirror: always + # Is support for Window.paintWorklet enabled? - name: dom.paintWorklet.enabled type: bool