mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1465251 - use PrioEncoder to encode Telemetry values for pilot project r=kmag
Use PrioEncoder to encode a few already-included histograms, so we can compare results on the Telemetry server side. Differential Revision: https://phabricator.services.mozilla.com/D5088 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
4b2a583e7c
commit
7d4c15f217
@ -1759,9 +1759,19 @@ pref("app.shield.optoutstudies.enabled", false);
|
||||
pref("intl.multilingual.enabled", false);
|
||||
|
||||
// Prio preferences
|
||||
// Only enable by default on Nightly.
|
||||
// On platforms that do not build libprio, do not set these prefs at all, which gives us a way to detect support.
|
||||
|
||||
// Curve25519 public keys for Prio servers
|
||||
#ifdef MOZ_LIBPRIO
|
||||
pref("prio.publicKeyA", "35AC1C7576C7C6EDD7FED6BCFC337B34D48CB4EE45C86BEEFB40BD8875707733");
|
||||
pref("prio.publicKeyB", "26E6674E65425B823F1F1D5F96E3BB3EF9E406EC7FBA7DEF8B08A35DD135AF50");
|
||||
#endif
|
||||
|
||||
// Whether or not Prio-encoded Telemetry will be sent along with the main ping.
|
||||
#if defined(NIGHTLY_BUILD) && defined(MOZ_LIBPRIO)
|
||||
pref("prio.enabled", true);
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("browser.fastblock.enabled", true);
|
||||
|
@ -45,6 +45,9 @@ for cdm in CONFIG['MOZ_EME_MODULES']:
|
||||
if CONFIG['MOZ_GPSD']:
|
||||
DEFINES['MOZ_GPSD'] = True
|
||||
|
||||
if CONFIG['MOZ_LIBPRIO']:
|
||||
DEFINES['MOZ_LIBPRIO'] = True
|
||||
|
||||
# These files are specified in this moz.build to pick up DIST_SUBDIR as set in
|
||||
# this directory, which is un-set in browser/app.
|
||||
JS_PREFERENCE_PP_FILES += [
|
||||
|
@ -7,13 +7,13 @@
|
||||
[ChromeOnly, Exposed=(Window,System)]
|
||||
namespace PrioEncoder {
|
||||
[Throws, NewObject]
|
||||
Promise<PrioEncodedData> encode(ByteString batchID, PrioParams params);
|
||||
PrioEncodedData encode(ByteString batchID, PrioParams params);
|
||||
};
|
||||
|
||||
dictionary PrioParams {
|
||||
required boolean startupCrashDetected;
|
||||
required boolean safeModeUsage;
|
||||
required boolean browserIsUserDefault;
|
||||
required boolean newTabPageEnabled;
|
||||
required boolean pdfViewerUsed;
|
||||
};
|
||||
|
||||
dictionary PrioEncodedData {
|
||||
|
@ -5,10 +5,13 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/TextUtils.h"
|
||||
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
|
||||
#include "PrioEncoder.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -35,15 +38,17 @@ PrioEncoder::~PrioEncoder()
|
||||
Prio_clear();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<Promise>
|
||||
PrioEncoder::Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const PrioParams& aPrioParams, ErrorResult& aRv)
|
||||
/* static */ void
|
||||
PrioEncoder::Encode(GlobalObject& aGlobal,
|
||||
const nsCString& aBatchID,
|
||||
const PrioParams& aPrioParams,
|
||||
RootedDictionary<PrioEncodedData>& aData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
SECStatus prio_rv = SECSuccess;
|
||||
@ -55,18 +60,20 @@ PrioEncoder::Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const Prio
|
||||
|
||||
Prio_init();
|
||||
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyA;
|
||||
nsresult rv = Preferences::GetCString("prio.publicKeyA", prioKeyA);
|
||||
rv = Preferences::GetCString("prio.publicKeyA", prioKeyA);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyB;
|
||||
rv = Preferences::GetCString("prio.publicKeyB", prioKeyB);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that both public keys are of the right length
|
||||
@ -74,35 +81,41 @@ PrioEncoder::Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const Prio
|
||||
if (!PrioEncoder::IsValidHexPublicKey(prioKeyA)
|
||||
|| !PrioEncoder::IsValidHexPublicKey(prioKeyB)) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
prio_rv = PublicKey_import_hex(&sPublicKeyA, reinterpret_cast<const unsigned char*>(prioKeyA.BeginReading()), CURVE25519_KEY_LEN_HEX);
|
||||
prio_rv = PublicKey_import_hex(&sPublicKeyA,
|
||||
reinterpret_cast<const unsigned char*>(prioKeyA.BeginReading()),
|
||||
CURVE25519_KEY_LEN_HEX);
|
||||
if (prio_rv != SECSuccess) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
prio_rv = PublicKey_import_hex(&sPublicKeyB, reinterpret_cast<const unsigned char*>(prioKeyB.BeginReading()), CURVE25519_KEY_LEN_HEX);
|
||||
prio_rv = PublicKey_import_hex(&sPublicKeyB,
|
||||
reinterpret_cast<const unsigned char*>(prioKeyB.BeginReading()),
|
||||
CURVE25519_KEY_LEN_HEX);
|
||||
if (prio_rv != SECSuccess) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
|
||||
bool dataItems[] = {
|
||||
aPrioParams.mStartupCrashDetected,
|
||||
aPrioParams.mSafeModeUsage,
|
||||
aPrioParams.mBrowserIsUserDefault
|
||||
aPrioParams.mBrowserIsUserDefault,
|
||||
aPrioParams.mNewTabPageEnabled,
|
||||
aPrioParams.mPdfViewerUsed,
|
||||
};
|
||||
|
||||
PrioConfig prioConfig = PrioConfig_new(mozilla::ArrayLength(dataItems), sPublicKeyA, sPublicKeyB, reinterpret_cast<const unsigned char*>(aBatchID.BeginReading()), aBatchID.Length());
|
||||
PrioConfig prioConfig = PrioConfig_new(mozilla::ArrayLength(dataItems),
|
||||
sPublicKeyA,
|
||||
sPublicKeyB,
|
||||
reinterpret_cast<const unsigned char*>(aBatchID.BeginReading()),
|
||||
aBatchID.Length());
|
||||
|
||||
if (!prioConfig) {
|
||||
promise->MaybeReject(NS_ERROR_FAILURE);
|
||||
return promise.forget();
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
auto configGuard = MakeScopeExit([&] {
|
||||
@ -114,50 +127,54 @@ PrioEncoder::Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const Prio
|
||||
unsigned char* forServerB = nullptr;
|
||||
unsigned int lenB = 0;
|
||||
|
||||
prio_rv = PrioClient_encode(prioConfig, dataItems, &forServerA, &lenA, &forServerB, &lenB);
|
||||
|
||||
// Package the data into the dictionary
|
||||
PrioEncodedData data;
|
||||
prio_rv = PrioClient_encode(prioConfig,
|
||||
dataItems,
|
||||
&forServerA,
|
||||
&lenA,
|
||||
&forServerB,
|
||||
&lenB);
|
||||
|
||||
nsTArray<uint8_t> arrayForServerA;
|
||||
nsTArray<uint8_t> arrayForServerB;
|
||||
|
||||
if (!arrayForServerA.AppendElements(reinterpret_cast<uint8_t*>(forServerA), lenA, fallible)) {
|
||||
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return promise.forget();
|
||||
if (!arrayForServerA.AppendElements(reinterpret_cast<uint8_t*>(forServerA),
|
||||
lenA,
|
||||
fallible)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
free(forServerA);
|
||||
|
||||
if (!arrayForServerB.AppendElements(reinterpret_cast<uint8_t*>(forServerB), lenB, fallible)) {
|
||||
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return promise.forget();
|
||||
if (!arrayForServerB.AppendElements(reinterpret_cast<uint8_t*>(forServerB),
|
||||
lenB,
|
||||
fallible)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return ;
|
||||
}
|
||||
|
||||
free(forServerB);
|
||||
|
||||
if (prio_rv != SECSuccess) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> valueA(aGlobal.Context());
|
||||
if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerA), &valueA)) {
|
||||
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return promise.forget();
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
data.mA.Construct().Init(&valueA.toObject());
|
||||
|
||||
aData.mA.Construct().Init(&valueA.toObject());
|
||||
|
||||
JS::Rooted<JS::Value> valueB(aGlobal.Context());
|
||||
if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerB), &valueB)) {
|
||||
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return promise.forget();
|
||||
}
|
||||
data.mB.Construct().Init(&valueB.toObject());
|
||||
|
||||
if (prio_rv != SECSuccess) {
|
||||
promise->MaybeReject(NS_ERROR_FAILURE);
|
||||
return promise.forget();
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
promise->MaybeResolve(data);
|
||||
|
||||
return promise.forget();
|
||||
aData.mB.Construct().Init(&valueB.toObject());
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -21,8 +21,12 @@ class PrioEncoder
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(PrioEncoder)
|
||||
|
||||
static already_AddRefed<Promise>
|
||||
Encode(GlobalObject& aGlobal, const nsCString& aBatchID, const PrioParams& aPrioParams, ErrorResult& aRv);
|
||||
static
|
||||
void Encode(GlobalObject& aGlobal,
|
||||
const nsCString& aBatchID,
|
||||
const PrioParams& aPrioParams,
|
||||
RootedDictionary<PrioEncodedData>& aData,
|
||||
ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
PrioEncoder();
|
||||
|
@ -5952,3 +5952,8 @@ pref("dom.datatransfer.mozAtAPIs", false);
|
||||
#else
|
||||
pref("dom.datatransfer.mozAtAPIs", true);
|
||||
#endif
|
||||
|
||||
// Whether or not Prio is supported on this platform.
|
||||
#ifdef MOZ_LIBPRIO
|
||||
pref("prio.enabled", false);
|
||||
#endif
|
||||
|
@ -677,6 +677,24 @@ Structure:
|
||||
...
|
||||
],
|
||||
|
||||
Prio
|
||||
----
|
||||
This section contains experimental data encoded with a basic version of the Prio system for private aggregation.
|
||||
See `the Prio paper <https://crypto.stanford.edu/prio/>`_ and `the libprio Github repo <https://github.com/mozilla/libprio>`_
|
||||
for more information.
|
||||
|
||||
Prio splits data packets into two "shares", signed for different servers that will do the decryption+decoding and
|
||||
aggregation. We call these "Server A" and "Server B", represented as `a` and `b` keys in `payload.prio`.
|
||||
|
||||
Structure:
|
||||
|
||||
.. code-block:: js
|
||||
"prio": {
|
||||
a: ... // Uint8Array containing data signed for Server A
|
||||
b: ... // Uint8Array containing data signed for Server B
|
||||
}
|
||||
|
||||
|
||||
Version History
|
||||
===============
|
||||
|
||||
|
@ -87,6 +87,9 @@ const TOPIC_CYCLE_COLLECTOR_BEGIN = "cycle-collector-begin";
|
||||
// How long to wait in millis for all the child memory reports to come in
|
||||
const TOTAL_MEMORY_COLLECTOR_TIMEOUT = 200;
|
||||
|
||||
// Control whether Telemetry data should be encrypted with Prio.
|
||||
const PRIO_ENABLED_PREF = "prio.enabled";
|
||||
|
||||
var gLastMemoryPoll = null;
|
||||
|
||||
var gWasDebuggerAttached = false;
|
||||
@ -1168,6 +1171,11 @@ var Impl = {
|
||||
|
||||
payloadObj.info = info;
|
||||
|
||||
// Collect Prio-encoded measurements.
|
||||
if (Services.prefs.getBoolPref(PRIO_ENABLED_PREF, false)) {
|
||||
payloadObj.prio = protect(() => this._prioEncode());
|
||||
}
|
||||
|
||||
// Add extended set measurements for chrome process.
|
||||
if (Telemetry.canRecordExtended) {
|
||||
payloadObj.slowSQL = protect(() => Telemetry.slowSQL);
|
||||
@ -1947,4 +1955,44 @@ var Impl = {
|
||||
this._newProfilePingSent = true;
|
||||
return TelemetryStorage.saveSessionData(this._getSessionDataObject());
|
||||
},
|
||||
|
||||
/**
|
||||
* Encodes data for experimental Prio pilot project.
|
||||
*
|
||||
* @return {Object} An object containing Prio-encoded data.
|
||||
*/
|
||||
_prioEncode() {
|
||||
// First, map the Telemetry histogram names to the params PrioEncoder.encode() expects.
|
||||
const prioEncodedHistograms = {
|
||||
"BROWSER_IS_USER_DEFAULT": "browserIsUserDefault",
|
||||
"NEWTAB_PAGE_ENABLED": "newTabPageEnabled",
|
||||
"PDF_VIEWER_USED": "pdfViewerUsed",
|
||||
};
|
||||
|
||||
// Build list of Prio parameters, using the first value recorded in each histogram.
|
||||
let prioParams = {};
|
||||
for (const [histogramName, prioName] of Object.entries(prioEncodedHistograms)) {
|
||||
try {
|
||||
const histogram = Telemetry.getHistogramById(histogramName);
|
||||
const firstCount = Boolean(histogram.snapshot().sum);
|
||||
prioParams[prioName] = firstCount;
|
||||
|
||||
} catch (ex) {
|
||||
this._log.error(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Prio encode the data and add to payload.
|
||||
const batchID = Policy.now();
|
||||
|
||||
let prioEncodedData;
|
||||
|
||||
try {
|
||||
prioEncodedData = PrioEncoder.encode(batchID, prioParams);
|
||||
} catch (ex) {
|
||||
this._log.error(ex);
|
||||
}
|
||||
|
||||
return prioEncodedData;
|
||||
},
|
||||
};
|
||||
|
@ -403,6 +403,11 @@ function checkPayload(payload, reason, successfulPings) {
|
||||
|
||||
Assert.ok("processes" in payload, "The payload must have a processes section.");
|
||||
Assert.ok("parent" in payload.processes, "There must be at least a parent process.");
|
||||
|
||||
if (Services.prefs.getBoolPref("prio.enabled", false)) {
|
||||
Assert.ok("prio" in payload, "The payload must have a prio section.");
|
||||
}
|
||||
|
||||
checkScalars(payload.processes);
|
||||
}
|
||||
|
||||
|
@ -1070,10 +1070,12 @@ set_define('MOZ_LAUNCHER_PROCESS', launcher)
|
||||
|
||||
# Prio
|
||||
# ==============================================================
|
||||
@depends(c_compiler)
|
||||
def libprio(info):
|
||||
@depends(c_compiler, target)
|
||||
def libprio(info, target):
|
||||
if info:
|
||||
if info.type in ('msvc',):
|
||||
# TODO - re-enable Windows when bug 1489691 is fixed.
|
||||
# Note that we will probably never support MSVC however.
|
||||
if info.type in ('msvc',) or target.os in ('WINNT',):
|
||||
return None
|
||||
return True
|
||||
|
||||
|
@ -55,6 +55,7 @@ module.exports = {
|
||||
// Specific to Firefox (Chrome code only).
|
||||
"PlacesObservers": false,
|
||||
"PlacesWeakCallbackWrapper": false,
|
||||
"PrioEncoder": false,
|
||||
// Specific to Firefox (Chrome code only).
|
||||
"SharedArrayBuffer": false,
|
||||
"SimpleGestureEvent": false,
|
||||
|
Loading…
Reference in New Issue
Block a user