未验证 提交 5632c492 编写于 作者: S SteVen Batten 提交者: GitHub

fix mac address resolution on touchbar devices (#77033)

* fix mac address issue

* add event for machineId disambig

* convert to async for readability

* address comments

* getMac - clean up timeout handling

* app - merge machine id handling into one
上级 f092dbc0
......@@ -29,7 +29,6 @@
},
"dependencies": {
"applicationinsights": "1.0.8",
"getmac": "1.4.1",
"graceful-fs": "4.1.11",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1",
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module getmac {
export function getMac(callback: (error: Error, macAddress: string) => void): void;
}
declare module 'getmac' {
export = getmac;
}
\ No newline at end of file
......@@ -7,6 +7,7 @@ import * as errors from 'vs/base/common/errors';
import * as uuid from 'vs/base/common/uuid';
import { networkInterfaces } from 'os';
import { TernarySearchTree } from 'vs/base/common/map';
import { getMac } from 'vs/base/node/macAddress';
// http://www.techrepublic.com/blog/data-center/mac-address-scorecard-for-common-virtual-machine-platforms/
// VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69
......@@ -76,35 +77,25 @@ export const virtualMachineHint: { value(): number } = new class {
};
let machineId: Promise<string>;
export function getMachineId(): Promise<string> {
return machineId || (machineId = getMacMachineId()
.then(id => id || uuid.generateUuid())); // fallback, generate a UUID
}
export async function getMachineId(): Promise<string> {
if (!machineId) {
machineId = (async () => {
const id = await getMacMachineId();
function getMacMachineId(): Promise<string> {
return new Promise<string>(resolve => {
Promise.all([import('crypto'), import('getmac')]).then(([crypto, getmac]) => {
try {
getmac.getMac((error, macAddress) => {
if (!error) {
resolve(crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex'));
} else {
resolve(undefined);
}
});
return id || uuid.generateUuid(); // fallback, generate a UUID
})();
}
// Timeout due to hang with reduced privileges #58392
// TODO@sbatten: Remove this when getmac is patched
setTimeout(() => {
resolve(undefined);
}, 10000);
} catch (err) {
errors.onUnexpectedError(err);
resolve(undefined);
}
}, err => {
errors.onUnexpectedError(err);
resolve(undefined);
});
});
return machineId;
}
async function getMacMachineId(): Promise<string | undefined> {
try {
const crypto = await import('crypto');
const macAddress = await getMac();
return crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex');
} catch (err) {
errors.onUnexpectedError(err);
return undefined;
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { exec } from 'child_process';
import { isWindows } from 'vs/base/common/platform';
const cmdline = {
windows: 'getmac.exe',
unix: '/sbin/ifconfig -a || /sbin/ip link'
};
const invalidMacAddresses = [
'00:00:00:00:00:00',
'ff:ff:ff:ff:ff:ff',
'ac:de:48:00:11:22'
];
function validateMacAddress(candidate: string): boolean {
let tempCandidate = candidate.replace(/\-/g, ':').toLowerCase();
for (let invalidMacAddress of invalidMacAddresses) {
if (invalidMacAddress === tempCandidate) {
return false;
}
}
return true;
}
export function getMac(): Promise<string> {
return new Promise(async (resolve, reject) => {
const timeout = setTimeout(() => reject('Unable to retrieve mac address (timeout after 10s)'), 10000);
try {
resolve(await doGetMac());
} catch (error) {
reject(error);
} finally {
clearTimeout(timeout);
}
});
}
function doGetMac(): Promise<string> {
return new Promise((resolve, reject) => {
try {
exec(isWindows ? cmdline.windows : cmdline.unix, { timeout: 10000 }, (err, stdout, stdin) => {
if (err) {
return reject(`Unable to retrieve mac address (${err.toString()})`);
} else {
const regex = /(?:[a-f\d]{2}[:\-]){5}[a-f\d]{2}/gi;
let match;
while ((match = regex.exec(stdout)) !== null) {
const macAddressCandidate = match[0];
if (validateMacAddress(macAddressCandidate)) {
return resolve(macAddressCandidate);
}
}
return reject('Unable to retrieve mac address (unexpected format)');
}
});
} catch (err) {
reject(err);
}
});
}
\ No newline at end of file
......@@ -3,8 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as getmac from 'getmac';
import { getMachineId } from 'vs/base/node/id';
import { getMac } from 'vs/base/node/macAddress';
suite('ID', () => {
......@@ -16,9 +16,7 @@ suite('ID', () => {
});
test('getMac', () => {
return new Promise<string>((resolve, reject) => {
getmac.getMac((err, macAddress) => err ? reject(err) : resolve(macAddress));
}).then(macAddress => {
return getMac().then(macAddress => {
assert.ok(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(macAddress), `Expected a MAC address, got: ${macAddress}`);
});
});
......
......@@ -90,6 +90,7 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro
export class CodeApplication extends Disposable {
private static readonly MACHINE_ID_KEY = 'telemetry.machineId';
private static readonly TRUE_MACHINE_ID_KEY = 'telemetry.trueMachineId';
private windowsMainService: IWindowsMainService | undefined;
......@@ -363,8 +364,8 @@ export class CodeApplication extends Disposable {
// Resolve unique machine ID
this.logService.trace('Resolving machine identifier...');
const machineId = await this.resolveMachineId();
this.logService.trace(`Resolved machine identifier: ${machineId}`);
const { machineId, trueMachineId } = await this.resolveMachineId();
this.logService.trace(`Resolved machine identifier: ${machineId} (trueMachineId: ${trueMachineId})`);
// Spawn shared process after the first window has opened and 3s have passed
const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv);
......@@ -378,7 +379,7 @@ export class CodeApplication extends Disposable {
});
// Services
const appInstantiationService = await this.createServices(machineId, sharedProcess, sharedProcessClient);
const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessClient);
// Create driver
if (this.environmentService.driverHandle) {
......@@ -404,7 +405,7 @@ export class CodeApplication extends Disposable {
}
}
private async resolveMachineId(): Promise<string> {
private async resolveMachineId(): Promise<{ machineId: string, trueMachineId?: string }> {
// We cache the machineId for faster lookups on startup
// and resolve it only once initially if not cached
......@@ -415,10 +416,21 @@ export class CodeApplication extends Disposable {
this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId);
}
return machineId;
// Check if machineId is hashed iBridge Device
let trueMachineId: string | undefined;
if (isMacintosh && machineId === '6c9d2bc8f91b89624add29c0abeae7fb42bf539fa1cdb2e3e57cd668fa9bcead') {
trueMachineId = this.stateService.getItem<string>(CodeApplication.TRUE_MACHINE_ID_KEY);
if (!trueMachineId) {
trueMachineId = await getMachineId();
this.stateService.setItem(CodeApplication.TRUE_MACHINE_ID_KEY, trueMachineId);
}
}
return { machineId, trueMachineId };
}
private async createServices(machineId: string, sharedProcess: SharedProcess, sharedProcessClient: Promise<Client<string>>): Promise<IInstantiationService> {
private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessClient: Promise<Client<string>>): Promise<IInstantiationService> {
const services = new ServiceCollection();
// Files
......@@ -473,7 +485,7 @@ export class CodeApplication extends Disposable {
const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService));
const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath);
const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath];
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths };
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, trueMachineId };
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config]));
} else {
......
......@@ -19,6 +19,7 @@ export interface ITelemetryServiceConfig {
appender: ITelemetryAppender;
commonProperties?: Promise<{ [name: string]: any }>;
piiPaths?: string[];
trueMachineId?: string;
}
export class TelemetryService implements ITelemetryService {
......@@ -74,6 +75,15 @@ export class TelemetryService implements ITelemetryService {
}
*/
this.publicLog('machineIdFallback', { usingFallbackGuid: !isHashedId });
if (config.trueMachineId) {
/* __GDPR__
"machineIdDisambiguation" : {
"correctedMachineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
}
*/
this.publicLog('machineIdDisambiguation', { correctedMachineId: config.trueMachineId });
}
});
}
}
......
......@@ -2421,14 +2421,6 @@ each-props@^1.3.0:
is-plain-object "^2.0.1"
object.defaults "^1.1.0"
eachr@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/eachr/-/eachr-3.2.0.tgz#2c35e43ea086516f7997cf80b7aa64d55a4a4484"
integrity sha1-LDXkPqCGUW95l8+At6pk1VpKRIQ=
dependencies:
editions "^1.1.1"
typechecker "^4.3.0"
ecc-jsbn@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
......@@ -2446,11 +2438,6 @@ ecstatic@^3.0.0:
minimist "^1.1.0"
url-join "^2.0.5"
editions@^1.1.1, editions@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b"
integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==
editorconfig@^0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.15.0.tgz#b6dd4a0b6b9e76ce48e066bdc15381aebb8804fd"
......@@ -3078,15 +3065,6 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
extract-opts@^3.2.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/extract-opts/-/extract-opts-3.3.1.tgz#5abbedc98c0d5202e3278727f9192d7e086c6be1"
integrity sha1-WrvtyYwNUgLjJ4cn+Rktfghsa+E=
dependencies:
eachr "^3.2.0"
editions "^1.1.1"
typechecker "^4.3.0"
extract-zip@^1.6.5:
version "1.6.6"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c"
......@@ -3579,14 +3557,6 @@ get-value@^2.0.3, get-value@^2.0.6:
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
getmac@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/getmac/-/getmac-1.4.1.tgz#cfefcb3ee7d7a73cba5292129cb100c19afbe17a"
integrity sha512-mQp+8D+grQX0gG8EJn6VfH0PxE56ZKNsTguOMxPShAiVk9lvH8Ey36eXepG705Ac1HCsvaSrQ/6bPHZ0++F/Mg==
dependencies:
editions "^1.3.4"
extract-opts "^3.2.0"
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
......@@ -9087,13 +9057,6 @@ type-is@~1.6.15:
media-typer "0.3.0"
mime-types "~2.1.15"
typechecker@^4.3.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/typechecker/-/typechecker-4.5.0.tgz#c382920097812364bbaf4595b0ab6588244117a6"
integrity sha512-bqPE/ck3bVIaXP7gMKTKSHrypT32lpYTpiqzPYeYzdSQnmaGvaGhy7TnN/M/+5R+2rs/kKcp9ZLPRp/Q9Yj+4w==
dependencies:
editions "^1.3.4"
typed-rest-client@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-0.9.0.tgz#f768cc0dc3f4e950f06e04825c36b3e7834aa1f2"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册