@@ -52,29 +52,35 @@ import type {
5252 MongoshLoggingAndTelemetryArguments ,
5353 MongoshTrackingProperties ,
5454} from './types' ;
55- import { machineIdSync } from 'node-machine-id' ;
55+ import { machineId } from 'node-machine-id' ;
56+ import { createHmac } from 'crypto' ;
5657
5758export function setupLoggingAndTelemetry (
5859 props : MongoshLoggingAndTelemetryArguments
5960) : MongoshLoggingAndTelemetry {
60- if ( ! props . deviceId ) {
61- try {
62- props . deviceId = machineIdSync ( ) ;
63- } catch ( error ) {
64- props . bus . emit (
65- 'mongosh:error' ,
66- new Error ( 'Failed to get device ID' ) ,
67- 'telemetry'
68- ) ;
69- }
70- }
71-
7261 const loggingAndTelemetry = new LoggingAndTelemetry ( props ) ;
7362
7463 loggingAndTelemetry . setup ( ) ;
7564 return loggingAndTelemetry ;
7665}
7766
67+ /**
68+ * @returns A hashed, unique identifier for the running device.
69+ * @throws If something goes wrong when getting the device ID.
70+ */
71+ export async function getDeviceId ( ) : Promise < string > {
72+ // Create a hashed format from the all uppercase version of the machine ID
73+ // to match it exactly with the denisbrodbeck/machineid library that Atlas CLI uses.
74+ const originalId = ( await machineId ( true ) ) . toUpperCase ( ) ;
75+ const hmac = createHmac ( 'sha256' , originalId ) ;
76+
77+ /** This matches the message used to create the hashes in Atlas CLI */
78+ const DEVICE_ID_HASH_MESSAGE = 'atlascli' ;
79+
80+ hmac . update ( DEVICE_ID_HASH_MESSAGE ) ;
81+ return hmac . digest ( 'hex' ) ;
82+ }
83+
7884class LoggingAndTelemetry implements MongoshLoggingAndTelemetry {
7985 private static dummyLogger = new MongoLogWriter (
8086 '' ,
@@ -170,6 +176,7 @@ class LoggingAndTelemetry implements MongoshLoggingAndTelemetry {
170176 usesShellOption : false ,
171177 telemetryAnonymousId : undefined ,
172178 userId : undefined ,
179+ deviceId : undefined ,
173180 } ;
174181
175182 private setupBusEventListeners ( ) : void {
@@ -207,15 +214,47 @@ class LoggingAndTelemetry implements MongoshLoggingAndTelemetry {
207214 session_id : this . log . logId ,
208215 } ) ;
209216
217+ /** Eventually sets up the device ID and re-identifies the user. */
218+ const getCurrentDeviceId = async ( ) : Promise < string > => {
219+ try {
220+ this . busEventState . deviceId ??= this . deviceId ?? ( await getDeviceId ( ) ) ;
221+ } catch ( error ) {
222+ this . bus . emit ( 'mongosh:error' , error as Error , 'telemetry' ) ;
223+ this . busEventState . deviceId = 'unknown' ;
224+ }
225+ return this . busEventState . deviceId ;
226+ } ;
227+
210228 const getTelemetryUserIdentity = ( ) : MongoshAnalyticsIdentity => {
211229 return {
230+ deviceId : this . busEventState . deviceId ?? this . deviceId ,
212231 anonymousId :
213232 this . busEventState . telemetryAnonymousId ??
214233 ( this . busEventState . userId as string ) ,
215- deviceId : this . deviceId ,
216234 } ;
217235 } ;
218236
237+ const identifyUser = async ( ) : Promise < void > => {
238+ // We first instantly identify the user with the
239+ // current user information we have.
240+ this . analytics . identify ( {
241+ ...getTelemetryUserIdentity ( ) ,
242+ traits : getUserTraits ( ) ,
243+ } ) ;
244+
245+ if ( ! this . busEventState . deviceId ) {
246+ // If the Device ID had not been resolved yet,
247+ // we wait to resolve it and re-identify the user.
248+ this . busEventState . deviceId ??= await getCurrentDeviceId ( ) ;
249+
250+ this . analytics . identify ( {
251+ ...getTelemetryUserIdentity ( ) ,
252+ deviceId : await getCurrentDeviceId ( ) ,
253+ traits : getUserTraits ( ) ,
254+ } ) ;
255+ }
256+ } ;
257+
219258 onBus ( 'mongosh:start-mongosh-repl' , ( ev : StartMongoshReplEvent ) => {
220259 this . log . info (
221260 'MONGOSH' ,
@@ -301,10 +340,8 @@ class LoggingAndTelemetry implements MongoshLoggingAndTelemetry {
301340 }
302341 this . busEventState . telemetryAnonymousId =
303342 newTelemetryUserIdentity . anonymousId ;
304- this . analytics . identify ( {
305- ...getTelemetryUserIdentity ( ) ,
306- traits : getUserTraits ( ) ,
307- } ) ;
343+
344+ void identifyUser ( ) ;
308345 }
309346 ) ;
310347
@@ -320,10 +357,7 @@ class LoggingAndTelemetry implements MongoshLoggingAndTelemetry {
320357 } else {
321358 this . busEventState . userId = updatedTelemetryUserIdentity . userId ;
322359 }
323- this . analytics . identify ( {
324- ...getTelemetryUserIdentity ( ) ,
325- traits : getUserTraits ( ) ,
326- } ) ;
360+ void identifyUser ( ) ;
327361 this . log . info (
328362 'MONGOSH' ,
329363 mongoLogId ( 1_000_000_005 ) ,
0 commit comments