diff --git a/src/env/browser/machine.ts b/src/env/browser/machine.ts new file mode 100644 index 0000000000000..b6cc8fa90e8c9 --- /dev/null +++ b/src/env/browser/machine.ts @@ -0,0 +1,4 @@ +// This is intentional as the browser environment doesn't have access to MAC addresses +export function getMac(): string | undefined { + return undefined; +} diff --git a/src/env/node/machine.ts b/src/env/node/machine.ts new file mode 100644 index 0000000000000..8b35e348a9e4b --- /dev/null +++ b/src/env/node/machine.ts @@ -0,0 +1,50 @@ +import { createHash } from 'crypto'; +import { networkInterfaces } from 'os'; + +// Sourced from GKD +const knownBadAppIds = [ + // this appId corresponds to the 'iBridge Adapter for the Touchbar' on macbooks + // https://github.com/bevry/getmac/issues/42 + // https://discussions.apple.com/thread/7763102 + // discovered 3/21/23 with ~28,000 unique users + '8149453d12fde3c987f5ceb011360abe56307d17', // sha1('ac:de:48:00:11:22') + + // these appIds correspond to the default VMWARE vnet1 and vmnet8 interface mac address + // https://communities.vmware.com/t5/VMware-Workstation-Pro/Why-are-MAC-addresses-for-vmnet1-and-vmnet8-hardcoded/td-p/1580213 + // discovered 3/21/23 with 10250 unique users + 'a76a6cbfb93cbb6daa4c4836544564fb777a0803', // sha1('00-50-56-C0-00-01') + // discovered 3/22/23 with 3473 unique users + '4433e1caaca0b97ba94ef3e0772e5931f792fa9b', // sha1('00-50-56-C0-00-08') + + // this appId corresponds to the "Forticlient VPN client" adapter mac address + // https://community.fortinet.com/t5/Support-Forum/FortiClient-MAC-Address/m-p/60724 + // discovered 3/21/23 with 5655 unique users + 'b14e824ad9cd8a3e95493d48e6132ecce40e0e47', // sha1('00-09-0F-FE-00-01') +]; + +// Sourced from https://github.com/bevry/getmac/blob/master/source/index.ts +// There's issues with importing 'getmac' directly, so we referenced the relevant code here + +const zeroRegex = /(?:[0]{1,2}[:-]){5}[0]{1,2}/; +export function getMac(): string | undefined { + const list = networkInterfaces(); + + for (const parts of Object.values(list)) { + // for some reason beyond me, this is needed to satisfy typescript + // fix https://github.com/bevry/getmac/issues/100 + if (!parts) continue; + for (const part of parts) { + if (zeroRegex.test(part.mac) === false) { + const appId = sha1(part.mac); + if (appId != null && !knownBadAppIds.includes(appId)) { + return appId; + } + } + } + } + return undefined; +} + +function sha1(data: string): string | undefined { + return createHash('sha1').update(data, 'utf8').digest('hex'); +} diff --git a/src/extension.ts b/src/extension.ts index 1d1cfd8e2ad98..14c03e48fbde6 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -23,6 +23,7 @@ import { registerPartnerActionRunners } from './partners'; import { executeCommand, registerCommands } from './system/-webview/command'; import { configuration, Configuration } from './system/-webview/configuration'; import { setContext } from './system/-webview/context'; +import { getMachineId } from './system/-webview/machine'; import { Storage } from './system/-webview/storage'; import { deviceCohortGroup } from './system/-webview/vscode'; import { isTextDocument } from './system/-webview/vscode/documents'; @@ -56,7 +57,7 @@ export async function activate(context: ExtensionContext): Promise { diff --git a/src/telemetry/telemetry.ts b/src/telemetry/telemetry.ts index a1ba5915023de..b839ba0a5364b 100644 --- a/src/telemetry/telemetry.ts +++ b/src/telemetry/telemetry.ts @@ -6,6 +6,7 @@ import { getPlatform } from '@env/platform'; import type { Source, TelemetryEventData, TelemetryEvents, TelemetryGlobalContext } from '../constants.telemetry'; import type { Container } from '../container'; import { configuration } from '../system/-webview/configuration'; +import { getMachineId } from '../system/-webview/machine'; export interface TelemetryContext { env: string; @@ -99,7 +100,7 @@ export class TelemetryService implements Disposable { env: container.env, extensionId: container.id, extensionVersion: container.version, - machineId: env.machineId, + machineId: getMachineId(), sessionId: env.sessionId, language: env.language, platform: getPlatform(),