Skip to content

Commit

Permalink
feat(NODE-5008): add zstd and kerberos to peer deps (#3691)
Browse files Browse the repository at this point in the history
  • Loading branch information
durran authored Jun 6, 2023
1 parent 9f3cc02 commit 9561f32
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 32 deletions.
8 changes: 8 additions & 0 deletions package-lock.json

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

8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,21 @@
},
"peerDependencies": {
"@aws-sdk/credential-providers": "^3.201.0",
"@mongodb-js/zstd": "^1.1.0",
"kerberos": "^2.0.1",
"mongodb-client-encryption": ">=2.3.0 <3",
"snappy": "^7.2.2"
},
"peerDependenciesMeta": {
"@aws-sdk/credential-providers": {
"optional": true
},
"@mongodb-js/zstd": {
"optional": true
},
"kerberos": {
"optional": true
},
"snappy": {
"optional": true
},
Expand Down
20 changes: 16 additions & 4 deletions src/cmap/auth/gssapi.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as dns from 'dns';

import { Kerberos, type KerberosClient } from '../../deps';
import { getKerberos, type Kerberos, type KerberosClient } from '../../deps';
import { MongoInvalidArgumentError, MongoMissingCredentialsError } from '../../error';
import { ns } from '../../utils';
import type { Connection } from '../connection';
Expand Down Expand Up @@ -36,6 +36,8 @@ async function externalCommand(
}>;
}

let krb: typeof Kerberos;

export class GSSAPI extends AuthProvider {
override async auth(authContext: AuthContext): Promise<void> {
const { connection, credentials } = authContext;
Expand Down Expand Up @@ -77,10 +79,11 @@ async function makeKerberosClient(authContext: AuthContext): Promise<KerberosCli
);
}

if ('kModuleError' in Kerberos) {
throw Kerberos['kModuleError'];
loadKrb();
if ('kModuleError' in krb) {
throw krb['kModuleError'];
}
const { initializeClient } = Kerberos;
const { initializeClient } = krb;

const { username, password } = credentials;
const mechanismProperties = credentials.mechanismProperties as MechanismProperties;
Expand Down Expand Up @@ -190,3 +193,12 @@ export async function resolveCname(host: string): Promise<string> {
return host;
}
}

/**
* Load the Kerberos library.
*/
function loadKrb() {
if (!krb) {
krb = getKerberos();
}
}
57 changes: 36 additions & 21 deletions src/cmap/wire_protocol/compression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { promisify } from 'util';
import * as zlib from 'zlib';

import { LEGACY_HELLO_COMMAND } from '../../constants';
import { Snappy, ZStandard } from '../../deps';
import { getZstdLibrary, Snappy, type ZStandard } from '../../deps';
import { MongoDecompressionError, MongoInvalidArgumentError } from '../../error';

/** @public */
Expand Down Expand Up @@ -37,35 +37,39 @@ const ZSTD_COMPRESSION_LEVEL = 3;
const zlibInflate = promisify(zlib.inflate.bind(zlib));
const zlibDeflate = promisify(zlib.deflate.bind(zlib));

let zstd: typeof ZStandard;

// Facilitate compressing a message using an agreed compressor
export async function compress(
options: { zlibCompressionLevel: number; agreedCompressor: CompressorName },
dataToBeCompressed: Buffer
): Promise<Buffer> {
const zlibOptions = {} as zlib.ZlibOptions;
switch (options.agreedCompressor) {
case 'snappy':
case 'snappy': {
if ('kModuleError' in Snappy) {
throw Snappy['kModuleError'];
}
return Snappy.compress(dataToBeCompressed);

case 'zstd':
if ('kModuleError' in ZStandard) {
throw ZStandard['kModuleError'];
}
case 'zstd': {
loadZstd();
if ('kModuleError' in zstd) {
throw zstd['kModuleError'];
}
return ZStandard.compress(dataToBeCompressed, ZSTD_COMPRESSION_LEVEL);

case 'zlib':
return zstd.compress(dataToBeCompressed, ZSTD_COMPRESSION_LEVEL);
}
case 'zlib': {
if (options.zlibCompressionLevel) {
zlibOptions.level = options.zlibCompressionLevel;
}
return zlibDeflate(dataToBeCompressed, zlibOptions);

default:
}
default: {
throw new MongoInvalidArgumentError(
`Unknown compressor ${options.agreedCompressor} failed to compress`
);
}
}
}

Expand All @@ -83,22 +87,33 @@ export async function decompress(compressorID: number, compressedData: Buffer):
}

switch (compressorID) {
case Compressor.snappy:
case Compressor.snappy: {
if ('kModuleError' in Snappy) {
throw Snappy['kModuleError'];
}
return Snappy.uncompress(compressedData, { asBuffer: true });

case Compressor.zstd:
if ('kModuleError' in ZStandard) {
throw ZStandard['kModuleError'];
}
case Compressor.zstd: {
loadZstd();
if ('kModuleError' in zstd) {
throw zstd['kModuleError'];
}
return ZStandard.decompress(compressedData);

case Compressor.zlib:
return zstd.decompress(compressedData);
}
case Compressor.zlib: {
return zlibInflate(compressedData);

default:
}
default: {
return compressedData;
}
}
}

/**
* Load ZStandard if it is not already set.
*/
function loadZstd() {
if (!zstd) {
zstd = getZstdLibrary();
}
}
24 changes: 17 additions & 7 deletions src/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,15 @@ export let Kerberos: typeof import('kerberos') | { kModuleError: MongoMissingDep
)
);

try {
// Ensure you always wrap an optional require in the try block NODE-3199
Kerberos = require('kerberos');
} catch {} // eslint-disable-line
export function getKerberos(): typeof Kerberos | { kModuleError: MongoMissingDependencyError } {
try {
// Ensure you always wrap an optional require in the try block NODE-3199
Kerberos = require('kerberos');
return Kerberos;
} catch {
return Kerberos;
}
}

export interface KerberosClient {
step(challenge: string): Promise<string>;
Expand Down Expand Up @@ -62,9 +67,14 @@ export let ZStandard: ZStandardLib | { kModuleError: MongoMissingDependencyError
)
);

try {
ZStandard = require('@mongodb-js/zstd');
} catch {} // eslint-disable-line
export function getZstdLibrary(): typeof ZStandard | { kModuleError: MongoMissingDependencyError } {
try {
ZStandard = require('@mongodb-js/zstd');
return ZStandard;
} catch {
return ZStandard;
}
}

type CredentialProvider = {
fromNodeProviderChain(this: void): () => Promise<AWSCredentials>;
Expand Down
2 changes: 2 additions & 0 deletions test/action/dependency.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { dependencies, peerDependencies, peerDependenciesMeta } from '../../pack
const EXPECTED_DEPENDENCIES = ['bson', 'mongodb-connection-string-url', 'socks'];
const EXPECTED_PEER_DEPENDENCIES = [
'@aws-sdk/credential-providers',
'@mongodb-js/zstd',
'kerberos',
'snappy',
'mongodb-client-encryption'
];
Expand Down

0 comments on commit 9561f32

Please sign in to comment.