Skip to content

Commit 9c11195

Browse files
authored
Fix experiments hash parsing (#6492)
* Simplify & fix crypto.createHash * Add tests * Fix python test in news folder (#6398) * Fix broken python tests in news * Revert changes
1 parent ed501bf commit 9c11195

File tree

6 files changed

+39
-14
lines changed

6 files changed

+39
-14
lines changed

news/test_announce.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ def fake_git_rm(path):
187187

188188
def test_complete_news():
189189
version = "2019.3.0"
190-
date = datetime.date.today().strftime("%d %B %Y")
190+
# Remove leading `0`.
191+
date = datetime.date.today().strftime("%d %B %Y").lstrip("0")
191192
news = ann.complete_news(version, NEW_NEWS, f"{TITLE}\n\n\n{OLD_NEWS}")
192193
expected = f"{TITLE}\n\n## {version} ({date})\n\n{NEW_NEWS.strip()}\n\n\n{OLD_NEWS.strip()}"
193194
assert news == expected

src/client/common/crypto.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
// tslint:disable: no-any
66

7-
import { createHash, HexBase64Latin1Encoding } from 'crypto';
7+
import { createHash } from 'crypto';
88
import { injectable } from 'inversify';
99
import { ICryptoUtils, IHashFormat } from './types';
1010

@@ -13,8 +13,8 @@ import { ICryptoUtils, IHashFormat } from './types';
1313
*/
1414
@injectable()
1515
export class CryptoUtils implements ICryptoUtils {
16-
public createHash<E extends keyof IHashFormat>(data: string, encoding: HexBase64Latin1Encoding, hashFormat: E): IHashFormat[E] {
17-
const hash = createHash('sha512').update(data).digest(encoding);
18-
return hashFormat === 'number' ? parseInt(hash, undefined) : hash as any;
16+
public createHash<E extends keyof IHashFormat>(data: string, hashFormat: E): IHashFormat[E] {
17+
const hash = createHash('sha512').update(data).digest('hex');
18+
return hashFormat === 'number' ? parseInt(hash, 16) : hash as any;
1919
}
2020
}

src/client/common/experiments.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ export class ExperimentsManager implements IExperimentsManager {
150150
if (typeof (this.appEnvironment.machineId) !== 'string') {
151151
throw new Error('Machine ID should be a string');
152152
}
153-
const hash = this.crypto.createHash(`${this.appEnvironment.machineId}+${salt}`, 'hex', 'number');
153+
const hash = this.crypto.createHash(`${this.appEnvironment.machineId}+${salt}`, 'number');
154154
return hash % 100 >= min && hash % 100 < max;
155155
}
156156

src/client/common/types.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT License.
33
'use strict';
44

5-
import { HexBase64Latin1Encoding } from 'crypto';
65
import { Socket } from 'net';
76
import { Request as RequestResult } from 'request';
87
import { ConfigurationTarget, DiagnosticSeverity, Disposable, DocumentSymbolProvider, Event, Extension, ExtensionContext, OutputChannel, Uri, WorkspaceEdit } from 'vscode';
@@ -439,10 +438,9 @@ export interface ICryptoUtils {
439438
* Creates hash using the data and encoding specified
440439
* @returns hash as number, or string
441440
* @param data The string to hash
442-
* @param encoding Data encoding to use
443441
* @param hashFormat Return format of the hash, number or string
444442
*/
445-
createHash<E extends keyof IHashFormat>(data: string, encoding: HexBase64Latin1Encoding, hashFormat: E): IHashFormat[E];
443+
createHash<E extends keyof IHashFormat>(data: string, hashFormat: E): IHashFormat[E];
446444
}
447445

448446
export const IAsyncDisposableRegistry = Symbol('IAsyncDisposableRegistry');

src/test/common/crypto.unit.test.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,37 @@ suite('Crypto Utils', async () => {
1212
crypto = new CryptoUtils();
1313
});
1414
test('If hashFormat equals `number`, method createHash() returns a number', async () => {
15-
const hash = crypto.createHash('blabla', 'hex', 'number');
15+
const hash = crypto.createHash('blabla', 'number');
1616
assert.typeOf(hash, 'number', 'Type should be a number');
1717
});
1818
test('If hashFormat equals `string`, method createHash() returns a string', async () => {
19-
const hash = crypto.createHash('blabla', 'hex', 'string');
19+
const hash = crypto.createHash('blabla', 'string');
2020
assert.typeOf(hash, 'string', 'Type should be a string');
2121
});
22+
test('If hashFormat equals `number`, the hash should not be NaN', async () => {
23+
let hash = crypto.createHash('test', 'number');
24+
assert.isNotNaN(hash, 'Number hash should not be NaN');
25+
hash = crypto.createHash('hash', 'number');
26+
assert.isNotNaN(hash, 'Number hash should not be NaN');
27+
hash = crypto.createHash('HASH1', 'number');
28+
assert.isNotNaN(hash, 'Number hash should not be NaN');
29+
});
30+
test('If hashFormat equals `string`, the hash should not be undefined', async () => {
31+
let hash = crypto.createHash('test', 'string');
32+
assert.isDefined(hash, 'String hash should not be undefined');
33+
hash = crypto.createHash('hash', 'string');
34+
assert.isDefined(hash, 'String hash should not be undefined');
35+
hash = crypto.createHash('HASH1', 'string');
36+
assert.isDefined(hash, 'String hash should not be undefined');
37+
});
38+
test('If hashFormat equals `number`, hashes with different data should return different number hashes', async () => {
39+
const hash1 = crypto.createHash('hash1', 'number');
40+
const hash2 = crypto.createHash('hash2', 'number');
41+
assert.notEqual(hash1, hash2, 'Hashes should be different numbers');
42+
});
43+
test('If hashFormat equals `string`, hashes with different data should return different string hashes', async () => {
44+
const hash1 = crypto.createHash('hash1', 'string');
45+
const hash2 = crypto.createHash('hash2', 'string');
46+
assert.notEqual(hash1, hash2, 'Hashes should be different strings');
47+
});
2248
});

src/test/common/experiments.unit.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -588,10 +588,10 @@ suite('A/B experiments', () => {
588588
expect(() => expManager.isUserInRange(79, 94, 'salt')).to.throw();
589589
} else if (testParams.error) {
590590
const error = new Error('Kaboom');
591-
when(crypto.createHash(anything(), 'hex', 'number')).thenThrow(error);
591+
when(crypto.createHash(anything(), 'number')).thenThrow(error);
592592
expect(() => expManager.isUserInRange(79, 94, 'salt')).to.throw(error);
593593
} else {
594-
when(crypto.createHash(anything(), 'hex', 'number')).thenReturn(testParams.hash);
594+
when(crypto.createHash(anything(), 'number')).thenReturn(testParams.hash);
595595
expect(expManager.isUserInRange(79, 94, 'salt')).to.equal(testParams.expectedResult, 'Incorrectly identified');
596596
}
597597
});
@@ -625,7 +625,7 @@ suite('A/B experiments', () => {
625625
.returns(() => testParams.experimentStorageValue);
626626
when(appEnvironment.machineId).thenReturn('101');
627627
if (testParams.hash) {
628-
when(crypto.createHash(anything(), 'hex', 'number')).thenReturn(testParams.hash);
628+
when(crypto.createHash(anything(), 'number')).thenReturn(testParams.hash);
629629
}
630630
expManager.populateUserExperiments();
631631
assert.deepEqual(expManager.userExperiments, testParams.expectedResult);

0 commit comments

Comments
 (0)