Skip to content

Commit 4b55eb9

Browse files
committed
Fix a bug where changing the salt would not invalidate the hash cache
1 parent 1f8c1f3 commit 4b55eb9

File tree

2 files changed

+67
-24
lines changed

2 files changed

+67
-24
lines changed

src/telemetrydeck.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default class TelemetryDeck {
3939
this.appID = appID;
4040
this.clientUser = clientUser;
4141
this.sessionID = sessionID ?? randomString();
42-
this.salt = salt;
42+
this.salt = salt ?? this.salt;
4343
this.testMode = testMode ?? this.testMode;
4444
this.cryptoDigest = cryptoDigest;
4545
}
@@ -90,27 +90,25 @@ export default class TelemetryDeck {
9090
return flushPromise;
9191
}
9292

93-
_clientUser = '';
93+
_clientUserAndSalt = '';
9494
_clientUserHashed = '';
9595

96-
async _hashedClientUser(clientUser) {
97-
if (clientUser !== this._clientUser) {
98-
this._clientUserHashed = await sha256(
99-
[this.clientUser, this.salt].join(''),
100-
this.cryptoDigest
101-
);
102-
this._clientUser = this.clientUser;
96+
async _hashedClientUser(clientUser, salt) {
97+
if (clientUser + salt !== this._clientUserAndSalt) {
98+
this._clientUserHashed = await sha256([clientUser, salt].join(''), this.cryptoDigest);
99+
this._clientUserAndSalt = clientUser + salt;
103100
}
104101

105102
return this._clientUserHashed;
106103
}
107104

108105
async _build(type, payload, options, receivedAt) {
109106
const { appID, testMode } = this;
110-
let { clientUser, sessionID } = this;
107+
let { clientUser, salt, sessionID } = this;
111108

112109
options = options ?? {};
113110
clientUser = options.clientUser ?? clientUser;
111+
salt = options.salt ?? salt;
114112
sessionID = options.sessionID ?? sessionID;
115113

116114
if (!type) {
@@ -125,7 +123,7 @@ export default class TelemetryDeck {
125123
throw new Error(`TelemetryDeck: "clientUser" is not set`);
126124
}
127125

128-
clientUser = await this._hashedClientUser(clientUser);
126+
clientUser = await this._hashedClientUser(clientUser, salt);
129127

130128
const body = {
131129
clientUser,

tests/sdk.test.js

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import FakeTimers from '@sinonjs/fake-timers';
44

55
import TelemetryDeck from '../src/telemetrydeck.js';
66

7+
const anonymousInHex = Buffer.from('anonymous').toString('hex');
8+
79
test.beforeEach((t) => {
810
const fake = sinon.fake(() => new Response('OK LOL'));
911

@@ -14,9 +16,7 @@ test.beforeEach((t) => {
1416
const random = sinon.fake.returns(0.4); // chosen by fair dice roll. guaranteed to be random.
1517
sinon.replace(Math, 'random', random);
1618

17-
t.context.cryptoDigest = sinon.fake.returns(
18-
Promise.resolve(Buffer.from('THIS IS NOT A REAL HASH'))
19-
);
19+
t.context.cryptoDigest = sinon.fake((_, value) => Promise.resolve(Buffer.from(value)));
2020
});
2121

2222
test.afterEach.always(() => {
@@ -68,7 +68,7 @@ test.serial('Can send a signal', async (t) => {
6868
fake.firstCall.args[1].body,
6969
JSON.stringify([
7070
{
71-
clientUser: '54484953204953204e4f542041205245414c2048415348',
71+
clientUser: anonymousInHex,
7272
sessionID: '255s0',
7373
appID: 'foo',
7474
type: 'test',
@@ -117,7 +117,7 @@ test.serial('Can send additional payload attributes', async (t) => {
117117
fake.firstCall.args[1].body,
118118
JSON.stringify([
119119
{
120-
clientUser: '54484953204953204e4f542041205245414c2048415348',
120+
clientUser: anonymousInHex,
121121
sessionID: '255s0',
122122
appID: 'foo',
123123
type: 'test',
@@ -143,6 +143,8 @@ test.serial('Can send a signal with salty user', async (t) => {
143143

144144
const response = await td.signal('test');
145145

146+
const saltyInHex = Buffer.from('salty').toString('hex');
147+
146148
t.is(await response.text(), 'OK LOL');
147149
t.is(fake.callCount, 1);
148150
t.is(fake.firstCall.args[0], 'https://nom.telemetrydeck.com/v2/');
@@ -152,7 +154,7 @@ test.serial('Can send a signal with salty user', async (t) => {
152154
fake.firstCall.args[1].body,
153155
JSON.stringify([
154156
{
155-
clientUser: '54484953204953204e4f542041205245414c2048415348',
157+
clientUser: anonymousInHex + saltyInHex,
156158
sessionID: '255s0',
157159
appID: 'foo',
158160
type: 'test',
@@ -183,7 +185,7 @@ test.serial('Can send a signal with sessionID', async (t) => {
183185
fake.firstCall.args[1].body,
184186
JSON.stringify([
185187
{
186-
clientUser: '54484953204953204e4f542041205245414c2048415348',
188+
clientUser: anonymousInHex,
187189
sessionID: '1234567890',
188190
appID: 'foo',
189191
type: 'test',
@@ -213,15 +215,15 @@ test.serial('Can queue signals and send them later', async (t) => {
213215
t.deepEqual(td.store.values(), [
214216
{
215217
appID: 'foo',
216-
clientUser: '54484953204953204e4f542041205245414c2048415348',
218+
clientUser: anonymousInHex,
217219
receivedAt: now.toISOString(),
218220
sessionID: '1234567890',
219221
telemetryClientVersion: 'JavaScriptSDK __PACKAGE_VERSION__',
220222
type: 'foo',
221223
},
222224
{
223225
appID: 'foo',
224-
clientUser: '54484953204953204e4f542041205245414c2048415348',
226+
clientUser: anonymousInHex,
225227
receivedAt: now.toISOString(),
226228
sessionID: '1234567890',
227229
telemetryClientVersion: 'JavaScriptSDK __PACKAGE_VERSION__',
@@ -241,7 +243,7 @@ test.serial('Can queue signals and send them later', async (t) => {
241243
fake.firstCall.args[1].body,
242244
JSON.stringify([
243245
{
244-
clientUser: '54484953204953204e4f542041205245414c2048415348',
246+
clientUser: anonymousInHex,
245247
sessionID: '1234567890',
246248
appID: 'foo',
247249
type: 'test',
@@ -253,15 +255,15 @@ test.serial('Can queue signals and send them later', async (t) => {
253255
fake.secondCall.args[1].body,
254256
JSON.stringify([
255257
{
256-
clientUser: '54484953204953204e4f542041205245414c2048415348',
258+
clientUser: anonymousInHex,
257259
sessionID: '1234567890',
258260
appID: 'foo',
259261
type: 'foo',
260262
telemetryClientVersion: `JavaScriptSDK __PACKAGE_VERSION__`,
261263
receivedAt: now.toISOString(),
262264
},
263265
{
264-
clientUser: '54484953204953204e4f542041205245414c2048415348',
266+
clientUser: anonymousInHex,
265267
sessionID: '1234567890',
266268
appID: 'foo',
267269
type: 'bar',
@@ -302,7 +304,7 @@ test.serial('Can build signal payloads', async (t) => {
302304
fake.firstCall.args[1].body,
303305
JSON.stringify([
304306
{
305-
clientUser: '54484953204953204e4f542041205245414c2048415348',
307+
clientUser: anonymousInHex,
306308
sessionID: '1234567890',
307309
appID: 'foo',
308310
type: 'test',
@@ -337,3 +339,46 @@ test.serial('Can find build-in crypto digest', async (t) => {
337339

338340
delete globalThis.crypto;
339341
});
342+
343+
test.serial('Changing the salt also changes the hash', async (t) => {
344+
const { fake, cryptoDigest } = t.context;
345+
346+
const td = new TelemetryDeck({
347+
appID: 'foo',
348+
clientUser: 'anonymous',
349+
sessionID: '1234567890',
350+
cryptoDigest,
351+
});
352+
353+
await td.signal('test');
354+
t.is(
355+
fake.firstCall.args[1].body,
356+
JSON.stringify([
357+
{
358+
clientUser: anonymousInHex,
359+
sessionID: '1234567890',
360+
appID: 'foo',
361+
type: 'test',
362+
telemetryClientVersion: 'JavaScriptSDK __PACKAGE_VERSION__',
363+
},
364+
])
365+
);
366+
367+
td.salt = 'salz';
368+
369+
const salzInHex = Buffer.from('salz').toString('hex');
370+
371+
await td.signal('test');
372+
t.is(
373+
fake.secondCall.args[1].body,
374+
JSON.stringify([
375+
{
376+
clientUser: anonymousInHex + salzInHex,
377+
sessionID: '1234567890',
378+
appID: 'foo',
379+
type: 'test',
380+
telemetryClientVersion: 'JavaScriptSDK __PACKAGE_VERSION__',
381+
},
382+
])
383+
);
384+
});

0 commit comments

Comments
 (0)