diff --git a/package-lock.json b/package-lock.json index bdc99fb6d24..2ad349e1ad1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47168,7 +47168,7 @@ "@mongodb-js/compass-user-data": "^0.11.2", "@mongodb-js/compass-utils": "^0.9.23", "@mongodb-js/connection-info": "^0.24.0", - "@mongodb-js/devtools-connect": "^3.9.7", + "@mongodb-js/devtools-connect": "^3.12.0", "@mongodb-js/devtools-proxy-support": "^0.5.5", "@mongodb-js/oidc-plugin": "^2.0.4", "compass-preferences-model": "^2.66.3", @@ -47197,6 +47197,30 @@ "typescript": "^5.9.3" } }, + "packages/atlas-service/node_modules/@mongodb-js/devtools-connect": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/devtools-connect/-/devtools-connect-3.12.0.tgz", + "integrity": "sha512-/aiGAKE5k6y1noI6hFo3pkLarNCNjEn+J3iqWTAMBuX4SpKUWsDdpMAyyxkqou7qH97gvon4A7wQafWFgWTXvA==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/devtools-proxy-support": "^0.5.5", + "@mongodb-js/oidc-http-server-pages": "1.1.8", + "lodash.merge": "^4.6.2", + "mongodb-connection-string-url": "^3.0.0", + "socks": "^2.7.3" + }, + "optionalDependencies": { + "kerberos": "^2.1.0", + "mongodb-client-encryption": "^6.1.0", + "os-dns-native": "^1.2.0", + "resolve-mongodb-srv": "^1.1.1" + }, + "peerDependencies": { + "@mongodb-js/oidc-plugin": "^2.0.0", + "mongodb": "^6.9.0", + "mongodb-log-writer": "^2.4.4" + } + }, "packages/atlas-service/node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -52570,7 +52594,7 @@ "license": "SSPL", "dependencies": { "@mongodb-js/compass-utils": "^0.9.23", - "@mongodb-js/devtools-connect": "^3.9.7", + "@mongodb-js/devtools-connect": "^3.12.0", "@mongodb-js/devtools-proxy-support": "^0.5.5", "bson": "^6.10.4", "debug": "^4.3.4", @@ -52605,6 +52629,30 @@ "mongodb-client-encryption": "^6.5.0" } }, + "packages/data-service/node_modules/@mongodb-js/devtools-connect": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/devtools-connect/-/devtools-connect-3.12.0.tgz", + "integrity": "sha512-/aiGAKE5k6y1noI6hFo3pkLarNCNjEn+J3iqWTAMBuX4SpKUWsDdpMAyyxkqou7qH97gvon4A7wQafWFgWTXvA==", + "license": "Apache-2.0", + "dependencies": { + "@mongodb-js/devtools-proxy-support": "^0.5.5", + "@mongodb-js/oidc-http-server-pages": "1.1.8", + "lodash.merge": "^4.6.2", + "mongodb-connection-string-url": "^3.0.0", + "socks": "^2.7.3" + }, + "optionalDependencies": { + "kerberos": "^2.1.0", + "mongodb-client-encryption": "^6.1.0", + "os-dns-native": "^1.2.0", + "resolve-mongodb-srv": "^1.1.1" + }, + "peerDependencies": { + "@mongodb-js/oidc-plugin": "^2.0.0", + "mongodb": "^6.9.0", + "mongodb-log-writer": "^2.4.4" + } + }, "packages/data-service/node_modules/@mongodb-js/devtools-docker-test-envs": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@mongodb-js/devtools-docker-test-envs/-/devtools-docker-test-envs-1.3.3.tgz", @@ -52667,7 +52715,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/kerberos/-/kerberos-2.2.1.tgz", "integrity": "sha512-Vlyv1tjAPb0y2VIJ03dKkUjsneGIBuTkH24uGRx6/DrKpFlVuGPmct3m5aEotljVUlw7PAGWABwR5aNeW7y8Zw==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -52682,7 +52730,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "packages/data-service/node_modules/sinon": { @@ -60756,7 +60804,7 @@ "@mongodb-js/compass-user-data": "^0.11.2", "@mongodb-js/compass-utils": "^0.9.23", "@mongodb-js/connection-info": "^0.24.0", - "@mongodb-js/devtools-connect": "^3.9.7", + "@mongodb-js/devtools-connect": "^3.12.0", "@mongodb-js/devtools-proxy-support": "^0.5.5", "@mongodb-js/eslint-config-compass": "^1.4.12", "@mongodb-js/mocha-config-compass": "^1.7.2", @@ -60783,6 +60831,22 @@ "typescript": "^5.9.3" }, "dependencies": { + "@mongodb-js/devtools-connect": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/devtools-connect/-/devtools-connect-3.12.0.tgz", + "integrity": "sha512-/aiGAKE5k6y1noI6hFo3pkLarNCNjEn+J3iqWTAMBuX4SpKUWsDdpMAyyxkqou7qH97gvon4A7wQafWFgWTXvA==", + "requires": { + "@mongodb-js/devtools-proxy-support": "^0.5.5", + "@mongodb-js/oidc-http-server-pages": "1.1.8", + "kerberos": "^2.1.0", + "lodash.merge": "^4.6.2", + "mongodb-client-encryption": "^6.1.0", + "mongodb-connection-string-url": "^3.0.0", + "os-dns-native": "^1.2.0", + "resolve-mongodb-srv": "^1.1.1", + "socks": "^2.7.3" + } + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -85618,7 +85682,7 @@ "requires": { "@mongodb-js/compass-test-server": "^0.3.25", "@mongodb-js/compass-utils": "^0.9.23", - "@mongodb-js/devtools-connect": "^3.9.7", + "@mongodb-js/devtools-connect": "^3.12.0", "@mongodb-js/devtools-docker-test-envs": "^1.3.3", "@mongodb-js/devtools-proxy-support": "^0.5.5", "@mongodb-js/eslint-config-compass": "^1.4.12", @@ -85648,6 +85712,22 @@ "typescript": "^5.9.3" }, "dependencies": { + "@mongodb-js/devtools-connect": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@mongodb-js/devtools-connect/-/devtools-connect-3.12.0.tgz", + "integrity": "sha512-/aiGAKE5k6y1noI6hFo3pkLarNCNjEn+J3iqWTAMBuX4SpKUWsDdpMAyyxkqou7qH97gvon4A7wQafWFgWTXvA==", + "requires": { + "@mongodb-js/devtools-proxy-support": "^0.5.5", + "@mongodb-js/oidc-http-server-pages": "1.1.8", + "kerberos": "^2.1.0", + "lodash.merge": "^4.6.2", + "mongodb-client-encryption": "^6.1.0", + "mongodb-connection-string-url": "^3.0.0", + "os-dns-native": "^1.2.0", + "resolve-mongodb-srv": "^1.1.1", + "socks": "^2.7.3" + } + }, "@mongodb-js/devtools-docker-test-envs": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@mongodb-js/devtools-docker-test-envs/-/devtools-docker-test-envs-1.3.3.tgz", @@ -85697,7 +85777,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/kerberos/-/kerberos-2.2.1.tgz", "integrity": "sha512-Vlyv1tjAPb0y2VIJ03dKkUjsneGIBuTkH24uGRx6/DrKpFlVuGPmct3m5aEotljVUlw7PAGWABwR5aNeW7y8Zw==", - "dev": true, + "devOptional": true, "requires": { "node-addon-api": "^6.1.0", "prebuild-install": "^7.1.2" @@ -85707,7 +85787,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", - "dev": true + "devOptional": true }, "sinon": { "version": "9.2.4", diff --git a/packages/atlas-service/package.json b/packages/atlas-service/package.json index 38b4ecb9c19..6ddb36983c4 100644 --- a/packages/atlas-service/package.json +++ b/packages/atlas-service/package.json @@ -76,7 +76,7 @@ "@mongodb-js/compass-user-data": "^0.11.2", "@mongodb-js/compass-utils": "^0.9.23", "@mongodb-js/connection-info": "^0.24.0", - "@mongodb-js/devtools-connect": "^3.9.7", + "@mongodb-js/devtools-connect": "^3.12.0", "@mongodb-js/devtools-proxy-support": "^0.5.5", "@mongodb-js/oidc-plugin": "^2.0.4", "compass-preferences-model": "^2.66.3", diff --git a/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts b/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts index caccb9f9608..6b00e234dc6 100644 --- a/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts +++ b/packages/compass-e2e-tests/helpers/compass-web-sandbox.ts @@ -208,7 +208,11 @@ export const getAtlasCloudSandboxDefaultConnections = ( str.password = dbPassword; return { id: name, - connectionOptions: { connectionString: String(str) }, + connectionOptions: { + connectionString: String(str), + // System CA certificates are not available in the browser environment + useSystemCA: false, + }, favorite: { name }, }; }); diff --git a/packages/compass-web/polyfills/@mongodb-js/devtools-connect/index.ts b/packages/compass-web/polyfills/@mongodb-js/devtools-connect/index.ts deleted file mode 100644 index 046692f9a4e..00000000000 --- a/packages/compass-web/polyfills/@mongodb-js/devtools-connect/index.ts +++ /dev/null @@ -1,38 +0,0 @@ -export function hookLogger() { - /* no-op */ -} -export async function connectMongoClient( - url: string, - options: any, - logger: any, - MongoClient: any -): Promise { - // Remove options not understood by the plain Node.js driver - delete options.proxy; - delete options.applyProxyToOIDC; - delete options.productDocsLink; - delete options.productName; - delete options.oidc; - delete options.parentState; - delete options.parentHandle; - options.__skipPingOnConnect = true; - const client = new MongoClient(url, options); - await client.connect(); - return { - client, - state: { - getStateShareServer() { - return Promise.resolve('Not Available'); - }, - oidcPlugin: { - logger, - serialize() { - return Promise.resolve(undefined); - }, - }, - destroy() { - return Promise.resolve(); - }, - }, - }; -} diff --git a/packages/compass-web/polyfills/@mongodb-js/devtools-proxy-support/index.ts b/packages/compass-web/polyfills/@mongodb-js/devtools-proxy-support/index.ts index 33189348b98..b356c5a39c3 100644 --- a/packages/compass-web/polyfills/@mongodb-js/devtools-proxy-support/index.ts +++ b/packages/compass-web/polyfills/@mongodb-js/devtools-proxy-support/index.ts @@ -1,6 +1,9 @@ export function createAgent(): void { // The original can return 'undefined' as well } +export function isExistingAgentInstance(): boolean { + return false; +} export function useOrCreateAgent(): void { // The original can return 'undefined' as well } @@ -10,14 +13,17 @@ export function createSocks5Tunnel(): void { export function hookLogger(): void { // no-op } -export function createFetch(): never { - throw new Error('node-fetch like-API not available in compass-web'); +export function createFetch(): typeof fetch { + return async () => + Promise.reject(new Error('node-fetch not available in compass web')); } -export function systemCA(): never { - throw new Error('system CA access not available in compass-web'); +export async function systemCA() { + await Promise.reject( + new Error('system CA access not available in compass-web') + ); } export function resetSystemCACache(): never { - throw new Error('system CA access not available in compass-web'); + throw new Error('reset system CA access not available in compass-web'); } // Explicitly web-compatible diff --git a/packages/compass-web/polyfills/@mongodb-js/oidc-plugin/index.ts b/packages/compass-web/polyfills/@mongodb-js/oidc-plugin/index.ts new file mode 100644 index 00000000000..bfe64886334 --- /dev/null +++ b/packages/compass-web/polyfills/@mongodb-js/oidc-plugin/index.ts @@ -0,0 +1,10 @@ +export function hookLoggerToMongoLogWriter() {} +export function createMongoDBOIDCPlugin({ logger }: any) { + return { + mongoClientOptions: {}, + logger, + /* eslint-disable @typescript-eslint/require-await */ + serialize: async () => '', + destroy: () => {}, + }; +} diff --git a/packages/compass-web/polyfills/net/index.ts b/packages/compass-web/polyfills/net/index.ts index ad90f48579a..898bb03a5c8 100644 --- a/packages/compass-web/polyfills/net/index.ts +++ b/packages/compass-web/polyfills/net/index.ts @@ -28,8 +28,12 @@ class Socket extends Duplex { lookup?: ConnectionOptions['lookup']; tls?: boolean; }) { + // WS does not support callback lookup + if ((lookup?.length ?? 0) > 0) lookup = undefined; + const { wsURL, ...atlasOptions } = lookup?.() ?? ({} as { wsURL?: string; clusterName?: string }); + this._ws = new WebSocket(wsURL ?? '/ws-proxy'); this._ws.binaryType = 'arraybuffer'; this._ws.addEventListener( @@ -157,8 +161,6 @@ export { isIPv4, isIPv6 } from 'is-ip'; export const isIP = (input: string) => ipVersion(input) ?? 0; export const createConnection = (options: { host: string; port: number }) => { const socket = new Socket(); - setTimeout(() => { - socket.connect(options); - }); + socket.connect(options); return socket; }; diff --git a/packages/compass-web/polyfills/os-dns-native/index.ts b/packages/compass-web/polyfills/os-dns-native/index.ts new file mode 100644 index 00000000000..612046acb46 --- /dev/null +++ b/packages/compass-web/polyfills/os-dns-native/index.ts @@ -0,0 +1,7 @@ +import { resolveSrv, resolveTxt } from '../dns'; + +export const wasNativelyLookedUp = () => false; +export const withNodeFallback = { + resolveSrv, + resolveTxt, +}; diff --git a/packages/compass-web/sandbox/sandbox-connection-storage.tsx b/packages/compass-web/sandbox/sandbox-connection-storage.tsx index aae40bd3da4..38ee6c9f126 100644 --- a/packages/compass-web/sandbox/sandbox-connection-storage.tsx +++ b/packages/compass-web/sandbox/sandbox-connection-storage.tsx @@ -36,11 +36,31 @@ class SandboxConnectionStorage implements ConnectionStorage { return [info.id, info]; }) ); + + // Ensure useSystemCA is set to false for all connections since system CA + // certificates are not available in the browser environment + private normalizeConnectionInfo(info: ConnectionInfo): ConnectionInfo { + return { + ...info, + connectionOptions: { + ...info.connectionOptions, + useSystemCA: false, + }, + }; + } + loadAll(): Promise { - return Promise.resolve(Array.from(this._connections.values())); + return Promise.resolve( + Array.from(this._connections.values()).map((info) => + this.normalizeConnectionInfo(info) + ) + ); } load({ id }: { id: string }): Promise { - return Promise.resolve(this._connections.get(id)); + const info = this._connections.get(id); + return Promise.resolve( + info ? this.normalizeConnectionInfo(info) : undefined + ); } save({ connectionInfo }: { connectionInfo: ConnectionInfo }): Promise { this._connections.set(connectionInfo.id, connectionInfo); diff --git a/packages/compass-web/src/connection-storage.tsx b/packages/compass-web/src/connection-storage.tsx index 5bc824d5c65..3b3bd5eda9d 100644 --- a/packages/compass-web/src/connection-storage.tsx +++ b/packages/compass-web/src/connection-storage.tsx @@ -138,6 +138,7 @@ export class AtlasCloudConnectionStorage ...connectionInfo, connectionOptions: { ...connectionInfo.connectionOptions, + useSystemCA: false, lookup: () => { return { wsURL: this.atlasService.driverProxyEndpoint( diff --git a/packages/compass-web/webpack.config.js b/packages/compass-web/webpack.config.js index bff3ec5ad3b..ff1e308c6b0 100644 --- a/packages/compass-web/webpack.config.js +++ b/packages/compass-web/webpack.config.js @@ -45,6 +45,7 @@ module.exports = (env, args) => { '@mongodb-js/devtools-proxy-support': localPolyfill( '@mongodb-js/devtools-proxy-support' ), + '@mongodb-js/oidc-plugin': localPolyfill('@mongodb-js/oidc-plugin'), ...(config.mode === 'production' ? { @@ -56,14 +57,6 @@ module.exports = (env, args) => { } : {}), - // Replace 'devtools-connect' with a package that just directly connects - // using the driver (= web-compatible driver) logic, because devtools-connect - // contains a lot of logic that makes sense in a desktop application/CLI but - // not in a web environment (DNS resolution, OIDC, CSFLE/QE, etc.) - '@mongodb-js/devtools-connect': localPolyfill( - '@mongodb-js/devtools-connect' - ), - // TODO(COMPASS-7407): compass-logging // hard to disable the whole thing while there are direct dependencies // on log-writer @@ -124,6 +117,7 @@ module.exports = (env, args) => { os: require.resolve('os-browserify/browser'), crypto: require.resolve('crypto-browserify'), dns: localPolyfill('dns'), + 'os-dns-native': localPolyfill('os-dns-native'), // Built-in Node.js modules imported by the driver directly and used in // ways that requires us to provide a no-op polyfill zlib: localPolyfill('zlib'), diff --git a/packages/connection-storage/src/compass-main-connection-storage.spec.ts b/packages/connection-storage/src/compass-main-connection-storage.spec.ts index 3cb992a386d..d88700f5e69 100644 --- a/packages/connection-storage/src/compass-main-connection-storage.spec.ts +++ b/packages/connection-storage/src/compass-main-connection-storage.spec.ts @@ -795,6 +795,7 @@ describe('ConnectionStorage', function () { oidc: {}, fleOptions: { storeCredentials: false }, lookup: () => ({} as any), + useSystemCA: true, }; await connectionStorage.save({ connectionInfo: { diff --git a/packages/data-service/package.json b/packages/data-service/package.json index dba53b69d12..0b4220fb265 100644 --- a/packages/data-service/package.json +++ b/packages/data-service/package.json @@ -53,7 +53,7 @@ }, "dependencies": { "@mongodb-js/compass-utils": "^0.9.23", - "@mongodb-js/devtools-connect": "^3.9.7", + "@mongodb-js/devtools-connect": "^3.12.0", "@mongodb-js/devtools-proxy-support": "^0.5.5", "bson": "^6.10.4", "debug": "^4.3.4", diff --git a/packages/data-service/src/connect-mongo-client.spec.ts b/packages/data-service/src/connect-mongo-client.spec.ts index f5349d5634f..f6edb830f39 100644 --- a/packages/data-service/src/connect-mongo-client.spec.ts +++ b/packages/data-service/src/connect-mongo-client.spec.ts @@ -14,6 +14,7 @@ import ConnectionString from 'mongodb-connection-string-url'; const defaultOptions = { productDocsLink: 'https://www.mongodb.com/docs/compass/', productName: 'MongoDB Compass', + useSystemCA: true, }; const setupListeners = () => { diff --git a/packages/data-service/src/connect-mongo-client.ts b/packages/data-service/src/connect-mongo-client.ts index e3726a6dce0..3eecc07458a 100644 --- a/packages/data-service/src/connect-mongo-client.ts +++ b/packages/data-service/src/connect-mongo-client.ts @@ -164,6 +164,7 @@ export async function connectMongoClientDataService({ productDocsLink: productDocsLink ?? 'https://www.mongodb.com/docs/compass/', monitorCommands: true, autoEncryption: connectionOptions.fleOptions?.autoEncryption, + useSystemCA: connectionOptions.useSystemCA ?? true, ...oidcOptions, }; diff --git a/packages/data-service/src/connection-options.ts b/packages/data-service/src/connection-options.ts index cc284f32fa5..d006dfce230 100644 --- a/packages/data-service/src/connection-options.ts +++ b/packages/data-service/src/connection-options.ts @@ -19,7 +19,8 @@ export type OIDCOptions = Omit< >[]; }; -export interface ConnectionOptions { +export interface ConnectionOptions + extends Pick { /** * The connection string to connect to the MongoDB instance including all options set by the user. */