Skip to content

Commit 5dc0b2c

Browse files
committed
node: fix machine id not being a UUID in some cases
1 parent f4b76ae commit 5dc0b2c

File tree

2 files changed

+56
-8
lines changed

2 files changed

+56
-8
lines changed

packages/node/src/attributes/MachineIdentitfierAttributeProvider.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { BacktraceAttributeProvider, IdGenerator } from '@backtrace/sdk-core';
22
import { execSync } from 'child_process';
3+
import crypto from 'crypto';
4+
5+
const UUID_REGEX = /[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/i;
6+
const DASHLESS_UUID_REGEX = /[a-f0-9]{32}/i;
37

48
export class MachineIdentitfierAttributeProvider implements BacktraceAttributeProvider {
59
public static readonly SUPPORTED_PLATFORMS = ['win32', 'darwin', 'linux', 'freebsd'];
@@ -15,21 +19,24 @@ export class MachineIdentitfierAttributeProvider implements BacktraceAttributePr
1519
public get type(): 'scoped' | 'dynamic' {
1620
return 'scoped';
1721
}
22+
1823
public get(): Record<string, unknown> {
19-
const guid = this.generateGuid() ?? IdGenerator.uuid();
24+
let machineId = this.getMachineId();
25+
if (machineId) {
26+
machineId = this.getValidGuid(machineId);
27+
} else {
28+
machineId = IdGenerator.uuid();
29+
}
2030

2131
return {
22-
[this.MACHINE_ID_ATTRIBUTE]: guid,
32+
[this.MACHINE_ID_ATTRIBUTE]: machineId,
2333
};
2434
}
2535

26-
public generateGuid() {
36+
public getMachineId() {
2737
switch (process.platform) {
2838
case 'win32': {
29-
return execSync(this.COMMANDS['win32'])
30-
.toString()
31-
.match(/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}/i)?.[0]
32-
.toLowerCase();
39+
return execSync(this.COMMANDS['win32']).toString().match(UUID_REGEX)?.[0].toLowerCase();
3340
}
3441
case 'darwin': {
3542
return execSync(this.COMMANDS[process.platform])
@@ -51,4 +58,21 @@ export class MachineIdentitfierAttributeProvider implements BacktraceAttributePr
5158
}
5259
}
5360
}
61+
62+
private getValidGuid(input: string) {
63+
if (input.length === 36 && UUID_REGEX.test(input)) {
64+
return input;
65+
}
66+
67+
if (input.length === 32 && DASHLESS_UUID_REGEX.test(input)) {
68+
return this.addDashesToUuid(input);
69+
}
70+
71+
const sha = crypto.createHash('sha1').update(input).digest('hex').substring(0, 32);
72+
return this.addDashesToUuid(sha);
73+
}
74+
75+
private addDashesToUuid(uuid: string) {
76+
return `${uuid.substring(0, 8)}-${uuid.substring(8, 12)}-${uuid.substring(12, 16)}-${uuid.substring(16, 20)}-${uuid.substring(20, 32)}`;
77+
}
5478
}

packages/node/tests/attributes/machineIdAttributeProviderTests.spec.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import crypto from 'crypto';
12
import { MachineIdentitfierAttributeProvider } from '../../src/attributes/MachineIdentitfierAttributeProvider.js';
23

34
describe('Machine id attribute provider test', () => {
@@ -6,7 +7,7 @@ describe('Machine id attribute provider test', () => {
67
const machineIdentifier1 = new MachineIdentitfierAttributeProvider();
78
const machineIdentifier2 = new MachineIdentitfierAttributeProvider();
89

9-
expect(machineIdentifier1.generateGuid()).toBe(machineIdentifier2.generateGuid());
10+
expect(machineIdentifier1.getMachineId()).toBe(machineIdentifier2.getMachineId());
1011
});
1112
}
1213

@@ -15,4 +16,27 @@ describe('Machine id attribute provider test', () => {
1516

1617
expect(machineIdentifier.get()['guid']).toBeDefined();
1718
});
19+
20+
it(`Should convert guid to a guid with dashes`, () => {
21+
const machineIdentifier = new MachineIdentitfierAttributeProvider();
22+
const uuid = crypto.randomUUID();
23+
24+
jest.spyOn(machineIdentifier, 'getMachineId').mockReturnValue(uuid.replace(/-/g, ''));
25+
26+
expect(machineIdentifier.get()['guid']).toEqual(uuid);
27+
});
28+
29+
it(`Should create a hash of guid if it is not a proper guid`, () => {
30+
const machineIdentifier = new MachineIdentitfierAttributeProvider();
31+
const guidResult = 'foo';
32+
const sha = crypto.createHash('sha1').update(guidResult).digest('hex').substring(0, 32);
33+
const expected = `${sha.substring(0, 8)}-${sha.substring(8, 12)}-${sha.substring(12, 16)}-${sha.substring(16, 20)}-${sha.substring(20, 32)}`;
34+
35+
// Sanity check for creating a dashed guid
36+
expect(expected.replace(/-/g, '')).toEqual(sha);
37+
38+
jest.spyOn(machineIdentifier, 'getMachineId').mockReturnValue(guidResult);
39+
40+
expect(machineIdentifier.get()['guid']).toEqual(expected);
41+
});
1842
});

0 commit comments

Comments
 (0)