Skip to content

Commit

Permalink
fix: resolve SRV hostname before passing it to mongodb-cloud-info VSC…
Browse files Browse the repository at this point in the history
…ODE-442

Right now, we are passing the first hostname from the connection string
to mongodb-cloud-info, regardless of whether the connection string is a
`mongodb://` connection string or a `mongodb+srv://` one.

In the latter case, telemetry gathering fails, because
mongodb-cloud-info expects the name of an actual host with associated
A or AAAA records (so that it can look up the host’s IP address),
not a SRV one.

Using resolve-mongodb-srv first matches what Compass does and
solves this issue.
  • Loading branch information
addaleax committed Sep 21, 2023
1 parent 7cb1ea2 commit 5b5acc6
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 5 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,7 @@
"react-dom": "^17.0.2",
"react-redux": "^8.1.1",
"redux": "^4.2.1",
"resolve-mongodb-srv": "^1.1.2",
"ts-log": "^2.2.5",
"uuid": "^8.3.2",
"vscode-languageclient": "^8.1.0",
Expand Down
32 changes: 27 additions & 5 deletions src/telemetry/connectionTelemetry.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { DataService } from 'mongodb-data-service';
import { getCloudInfo } from 'mongodb-cloud-info';
import mongoDBBuildInfo from 'mongodb-build-info';
import resolveMongodbSrv from 'resolve-mongodb-srv';

import { ConnectionTypes } from '../connectionController';
import { createLogger } from '../logging';
import ConnectionString from 'mongodb-connection-string-url';

const log = createLogger('connection telemetry helper');
// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand Down Expand Up @@ -34,14 +36,36 @@ type CloudInfo = {
publicCloudName?: string | null;
};

async function getHostnameForConnection(
connectionStringData: ConnectionString
): Promise<string | null> {
if (connectionStringData.isSRV) {
const uri = await resolveMongodbSrv(connectionStringData.toString()).catch(
() => null
);
if (!uri) {
return null;
}
connectionStringData = new ConnectionString(uri, {
looseValidation: true,
});
}

const [hostname] = (connectionStringData.hosts[0] ?? '').split(':');
return hostname;
}

async function getCloudInfoFromDataService(
firstServerHostname: string
dataService: DataService
): Promise<CloudInfo> {
const hostname = await getHostnameForConnection(
dataService.getConnectionString()
);
const cloudInfo: {
isAws?: boolean;
isAzure?: boolean;
isGcp?: boolean;
} = await getCloudInfo(firstServerHostname);
} = await getCloudInfo(hostname);

if (cloudInfo.isAws) {
return {
Expand Down Expand Up @@ -82,15 +106,13 @@ export async function getConnectionTelemetryProperties(

try {
const connectionString = dataService.getConnectionString();
const firstHost = connectionString.hosts[0] || '';
const [hostname] = firstHost.split(':');
const authMechanism = connectionString.searchParams.get('authMechanism');
const username = connectionString.username ? 'DEFAULT' : 'NONE';
const authStrategy = authMechanism ?? username;

const [instance, cloudInfo] = await Promise.all([
dataService.instance(),
getCloudInfoFromDataService(hostname),
getCloudInfoFromDataService(dataService),
]);

preparedProperties = {
Expand Down

0 comments on commit 5b5acc6

Please sign in to comment.