@rtcstats/rtcstats-shared 2.3.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/anonymize.js ADDED
@@ -0,0 +1,39 @@
1
+ import {decompressMethod} from './compression.js';
2
+ import {obfuscateAddress, obfuscateIpOrAddress} from './address-obfuscator.js';
3
+
4
+ // Anonymize addresses in either an rtcstats dump or a webrtc-internals JSON
5
+ // dump (passed as text). Returns a Blob with the anonymized contents in the
6
+ // same format, or undefined if the format is not recognized.
7
+ export function anonymizeBlob(textBlob) {
8
+ if (textBlob.startsWith('RTCStatsDump\n')) {
9
+ const lines = textBlob.split('\n').map(line => {
10
+ if (line.startsWith('RTCStatsDump') || line === '') {
11
+ return line;
12
+ }
13
+ const data = JSON.parse(line);
14
+ obfuscateAddress(decompressMethod(data[0]), data);
15
+ return JSON.stringify(data);
16
+ });
17
+ return new Blob([lines.join('\n')]);
18
+ } else if (textBlob.startsWith('{')) {
19
+ const json = JSON.parse(textBlob);
20
+ Object.keys(json.PeerConnections).forEach(id => {
21
+ const pc = json.PeerConnections[id];
22
+ Object.keys(pc.stats).forEach(statsId => {
23
+ const stats = pc.stats[statsId];
24
+ const parts = statsId.split('-');
25
+ const type = parts[parts.length - 1];
26
+ if (!['address', 'ip', 'relatedAddress'].includes(type)) return;
27
+ const values = JSON.parse(stats.values);
28
+ stats.values = JSON.stringify(values.map(obfuscateIpOrAddress));
29
+ });
30
+ pc.updateLog.forEach(traceEvent => {
31
+ if (!traceEvent.value) return;
32
+ const value = JSON.parse(traceEvent.value);
33
+ obfuscateAddress(traceEvent.type, [,, value]);
34
+ traceEvent.value = JSON.stringify(value);
35
+ });
36
+ });
37
+ return new Blob([JSON.stringify(json, null, ' ')]);
38
+ }
39
+ }
package/compression.js CHANGED
@@ -175,23 +175,29 @@ export function statsDecompression(baseStatsInput, delta) {
175
175
  delete newStats[id];
176
176
  return;
177
177
  }
178
+ // A timestamp carried explicitly in the delta differs from the
179
+ // collapsed top-level one and must not be overwritten below.
180
+ const hasOwnTimestamp = newStats[id] !== undefined &&
181
+ newStats[id].timestamp !== undefined;
178
182
  if (!newStats[id]) {
179
- newStats[id] = baseStats[id];
183
+ // Copy the report so the timestamp assignment below does not
184
+ // modify the base stats.
185
+ newStats[id] = Object.assign({}, baseStats[id]);
180
186
  } else {
181
187
  const report = baseStats[id];
182
188
  Object.keys(report).forEach(name => {
183
- if (!newStats[id][name]) {
189
+ if (newStats[id][name] === undefined) {
184
190
  newStats[id][name] = report[name];
185
- } else if (typeof(report[name]) === 'object') {
186
- const newObject = newStats[id][name];
187
- newStats[id][name] = report[name];
188
- Object.keys(newObject).forEach(key => {
189
- newStats[id][name][key] = newObject[key];
190
- });
191
+ } else if (typeof(report[name]) === 'object' &&
192
+ !Array.isArray(newStats[id][name])) {
193
+ // Merge into a copy so the nested object of the
194
+ // base stats is not modified. Arrays are serialized
195
+ // wholesale on change and take the new value.
196
+ newStats[id][name] = Object.assign({}, report[name], newStats[id][name]);
191
197
  } // Else: take the new value.
192
198
  });
193
199
  }
194
- if (timestamp !== undefined) {
200
+ if (timestamp !== undefined && !hasOwnTimestamp) {
195
201
  newStats[id].timestamp = timestamp;
196
202
  }
197
203
  });
@@ -367,12 +373,20 @@ const methodTable = {
367
373
  // getUserMedia and friends.
368
374
  'navigator.mediaDevices.getUserMedia': 60,
369
375
  'navigator.mediaDevices.getUserMediaOnSuccess': 61,
370
- 'navigator.mediaDevices.getUserMediaOnFailure': 62,
376
+ // 62 is not usable. It was originally assigned to
377
+ // getUserMediaOnFailure but a copy-paste bug duplicated the
378
+ // key onto 65, which was intended for getDisplayMediaOnFailure.
379
+ // The last duplicate key wins in an object literal, so released clients
380
+ // have always compressed getUserMediaOnFailure to 65.
381
+ 'navigator.mediaDevices.getUserMediaOnFailure': 65,
371
382
  'navigator.mediaDevices.getDisplayMedia': 63,
372
383
  'navigator.mediaDevices.getDisplayMediaOnSuccess': 64,
373
- 'navigator.mediaDevices.getUserMediaOnFailure': 65,
374
384
  'navigator.mediaDevices.enumerateDevices': 66,
375
385
  'navigator.mediaDevices.ondevicechange': 67,
386
+ // Decompression-only until the next major version bump, see below.
387
+ // This method is therefore not compressed.
388
+ // 'navigator.mediaDevices.getDisplayMediaOnFailure': 68,
389
+ // Next free method id: 69.
376
390
  // MediaStreamTrack methods and events.
377
391
  'MediaStreamTrack.stop': 70,
378
392
  'MediaStreamTrack.applyConstraints': 71,
@@ -386,6 +400,7 @@ const methodTable = {
386
400
  // These should be moved to the compression table at major version bumps.
387
401
  const methodTableDecompression = {
388
402
  1: 'getStats',
403
+ 68: 'navigator.mediaDevices.getDisplayMediaOnFailure',
389
404
  };
390
405
  const reverseMethodTable = Object.keys(methodTable).reduce((table, method) => {
391
406
  table[methodTable[method]] = method;
package/dump.js CHANGED
@@ -62,8 +62,9 @@ export async function readRTCStatsDump(blob) {
62
62
  const time = new Date(lastTime);
63
63
 
64
64
  if (method === 'getStats') { // delta-compressed stats
65
+ // statsDecompression does not modify its base stats argument.
65
66
  value = statsDecompression(baseStats[connection_id], value);
66
- baseStats[connection_id] = JSON.parse(JSON.stringify(value));
67
+ baseStats[connection_id] = value;
67
68
  } else if (method === 'setLocalDescription' && value &&
68
69
  // Workaround for Chrome <145 bug: https://source.chromium.org/chromium/chromium/src/+/4a2a384e43ea163127219548087e949fb00fa562
69
70
  connection_id !== 'undefined-undefined') {
@@ -312,3 +313,4 @@ export async function extractTracks(peerConnectionTrace) {
312
313
  }
313
314
  return tracks;
314
315
  }
316
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtcstats/rtcstats-shared",
3
- "version": "2.3.0",
3
+ "version": "2.5.0",
4
4
  "main": "index.js",
5
5
  "description": "gather WebRTC API traces and statistics",
6
6
  "type": "module",