author | Thom Chiovoloni <tchiovoloni@mozilla.com> |
Wed, 07 Sep 2016 16:49:21 -0400 | |
changeset 313699 | 0123be9d2c87873e5d32bfd4ba517efdb4f38e6f |
parent 313698 | cec9f17302dbc776fa3a43c3a3c81e7fee873f0f |
child 313700 | 58846175232c221d1d6eccfdd9e26c1d41044f98 |
push id | 32235 |
push user | ryanvm@gmail.com |
push date | Wed, 14 Sep 2016 00:03:56 +0000 |
treeherder | autoland@0123be9d2c87 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bsmedberg, markh |
bugs | 1299784 |
milestone | 51.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/services/crypto/modules/utils.js +++ b/services/crypto/modules/utils.js @@ -101,16 +101,23 @@ this.CryptoUtils = { sha1: function sha1(message) { return CommonUtils.bytesAsHex(CryptoUtils.UTF8AndSHA1(message)); }, sha1Base32: function sha1Base32(message) { return CommonUtils.encodeBase32(CryptoUtils.UTF8AndSHA1(message)); }, + sha256(message) { + let hasher = Cc["@mozilla.org/security/hash;1"] + .createInstance(Ci.nsICryptoHash); + hasher.init(hasher.SHA256); + return CommonUtils.bytesAsHex(CryptoUtils.digestUTF8(message, hasher)); + }, + /** * Produce an HMAC key object from a key string. */ makeHMACKey: function makeHMACKey(str) { return Svc.KeyFactory.keyFromString(Ci.nsIKeyObject.HMAC, str); }, /**
--- a/services/sync/modules/browserid_identity.js +++ b/services/sync/modules/browserid_identity.js @@ -116,16 +116,20 @@ this.BrowserIDManager.prototype = { hashedUID() { if (!this._token) { throw new Error("hashedUID: Don't have token"); } return this._token.hashed_fxa_uid }, + deviceID() { + return this._signedInUser && this._signedInUser.deviceId; + }, + initialize: function() { for (let topic of OBSERVER_TOPICS) { Services.obs.addObserver(this, topic, false); } // and a background fetch of account data just so we can set this.account, // so we have a username available before we've actually done a login. // XXX - this is actually a hack just for tests and really shouldn't be // necessary. Also, you'd think it would be safe to allow this.account to
--- a/services/sync/modules/telemetry.js +++ b/services/sync/modules/telemetry.js @@ -199,16 +199,17 @@ class TelemetryRecord { toJSON() { let result = { when: this.when, uid: this.uid, took: this.took, failureReason: this.failureReason, status: this.status, + deviceID: this.deviceID, }; let engines = []; for (let engine of this.engines) { engines.push(engine.toJSON()); } if (engines.length > 0) { result.engines = engines; } @@ -223,18 +224,26 @@ class TelemetryRecord { this.onEngineStop(this.currentEngine.name); } if (error) { this.failureReason = transformError(error); } try { this.uid = Weave.Service.identity.hashedUID(); + let deviceID = Weave.Service.identity.deviceID(); + if (deviceID) { + // Combine the raw device id with the metrics uid to create a stable + // unique identifier that can't be mapped back to the user's FxA + // identity without knowing the metrics HMAC key. + this.deviceID = Utils.sha256(deviceID + this.uid); + } } catch (e) { this.uid = "0".repeat(32); + this.deviceID = undefined; } // Check for engine statuses. -- We do this now, and not in engine.finished // to make sure any statuses that get set "late" are recorded for (let engine of this.engines) { let status = Status.engines[engine.name]; if (status && status !== constants.ENGINE_SUCCEEDED) { engine.status = status;
--- a/services/sync/modules/util.js +++ b/services/sync/modules/util.js @@ -47,16 +47,17 @@ this.Utils = { // Aliases from CryptoUtils. generateRandomBytes: CryptoUtils.generateRandomBytes, computeHTTPMACSHA1: CryptoUtils.computeHTTPMACSHA1, digestUTF8: CryptoUtils.digestUTF8, digestBytes: CryptoUtils.digestBytes, sha1: CryptoUtils.sha1, sha1Base32: CryptoUtils.sha1Base32, + sha256: CryptoUtils.sha256, makeHMACKey: CryptoUtils.makeHMACKey, makeHMACHasher: CryptoUtils.makeHMACHasher, hkdfExpand: CryptoUtils.hkdfExpand, pbkdf2Generate: CryptoUtils.pbkdf2Generate, deriveKeyFromPassphrase: CryptoUtils.deriveKeyFromPassphrase, getHTTPMACSHA1Header: CryptoUtils.getHTTPMACSHA1Header, /**
--- a/services/sync/tests/unit/sync_ping_schema.json +++ b/services/sync/tests/unit/sync_ping_schema.json @@ -21,16 +21,20 @@ "required": ["when", "uid", "took"], "properties": { "didLogin": { "type": "boolean" }, "when": { "type": "integer" }, "uid": { "type": "string", "pattern": "^[0-9a-f]{32}$" }, + "deviceID": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, "status": { "type": "object", "anyOf": [ { "required": ["sync"] }, { "required": ["service"] } ], "additionalProperties": false, "properties": {
--- a/toolkit/components/telemetry/docs/data/sync-ping.rst +++ b/toolkit/components/telemetry/docs/data/sync-ping.rst @@ -20,16 +20,17 @@ Structure: version: 1, discarded: <integer count> // Number of syncs discarded -- left out if zero. why: <string>, // Why did we submit the ping? Either "shutdown" or "schedule". // Array of recorded syncs. The ping is not submitted if this would be empty syncs: [{ when: <integer milliseconds since epoch>, took: <integer duration in milliseconds>, uid: <string>, // Hashed FxA unique ID, or string of 32 zeros. + deviceID: <string>, // Hashed FxA Device ID, hex string of 64 characters, not included if the user is not logged in. didLogin: <bool>, // Optional, is this the first sync after login? Excluded if we don't know. why: <string>, // Optional, why the sync occured, excluded if we don't know. // Optional, excluded if there was no error. failureReason: { name: <string>, // "httperror", "networkerror", "shutdownerror", etc. code: <integer>, // Only present for "httperror" and "networkerror". error: <string>, // Only present for "othererror" and "unexpectederror".