@@ -9,6 +9,7 @@ import type {
99 DeleteOptions ,
1010 MapReduceOptions ,
1111 ExplainOptions ,
12+ ServiceProvider ,
1213} from '@mongosh/service-provider-core' ;
1314import {
1415 CommonErrors ,
@@ -176,6 +177,35 @@ export function adaptOptions(
176177 } , additions ) ;
177178}
178179
180+ async function computeLegacyHexMD5 (
181+ sp : ServiceProvider ,
182+ str : string
183+ ) : Promise < string > {
184+ const digested = await sp . computeLegacyHexMD5 ?.( str ) ;
185+ if ( digested ) return digested ;
186+
187+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
188+ let crypto : typeof import ( 'crypto' ) ;
189+ try {
190+ // Try to dynamically import crypto so that we don't break plain-JS-runtime builds.
191+ // The Web Crypto API does not provide MD5, which is reasonable for a modern API
192+ // but means that we cannot use it as a fallback.
193+ crypto = require ( 'crypto' ) ;
194+ } catch {
195+ throw new MongoshUnimplementedError (
196+ 'Legacy password digest algorithms like SCRAM-SHA-1 are not supported by this instance of mongosh' ,
197+ CommonErrors . Deprecated
198+ ) ;
199+ }
200+ // NOTE: this code has raised a code scanning alert about the "use of a broken or weak cryptographic algorithm":
201+ // we inherited this code from `mongo`, and we cannot replace MD5 with a different algorithm, since MD5 is part of the SCRAM-SHA-1 protocol,
202+ // and the purpose of `passwordDigestor=client` is to improve the security of SCRAM-SHA-1, allowing the creation of new users
203+ // without the need to communicate their password to the server.
204+ const hash = crypto . createHash ( 'md5' ) ;
205+ hash . update ( str ) ;
206+ return hash . digest ( 'hex' ) ;
207+ }
208+
179209/**
180210 * Optionally digest password if passwordDigestor field set to 'client'. If it's false,
181211 * then hash the password.
@@ -184,11 +214,12 @@ export function adaptOptions(
184214 * @param passwordDigestor
185215 * @param {Object } command
186216 */
187- export function processDigestPassword (
217+ export async function processDigestPassword (
188218 username : string ,
189219 passwordDigestor : 'server' | 'client' ,
190- command : { pwd : string }
191- ) : { digestPassword ?: boolean ; pwd ?: string } {
220+ command : { pwd : string } ,
221+ sp : ServiceProvider
222+ ) : Promise < { digestPassword ?: boolean ; pwd ?: string } > {
192223 if ( passwordDigestor === undefined ) {
193224 return { } ;
194225 }
@@ -205,27 +236,10 @@ export function processDigestPassword(
205236 CommonErrors . InvalidArgument
206237 ) ;
207238 }
208- // eslint-disable-next-line @typescript-eslint/consistent-type-imports
209- let crypto : typeof import ( 'crypto' ) ;
210- try {
211- // Try to dynamically import crypto so that we don't break plain-JS-runtime builds.
212- // The Web Crypto API does not provide MD5, which is reasonable for a modern API
213- // but means that we cannot use it as a fallback.
214- crypto = require ( 'crypto' ) ;
215- } catch {
216- throw new MongoshUnimplementedError (
217- 'Legacy password digest algorithms like SCRAM-SHA-1 are not supported by this instance of mongosh' ,
218- CommonErrors . Deprecated
219- ) ;
220- }
221- // NOTE: this code has raised a code scanning alert about the "use of a broken or weak cryptographic algorithm":
222- // we inherited this code from `mongo`, and we cannot replace MD5 with a different algorithm, since MD5 is part of the SCRAM-SHA-1 protocol,
223- // and the purpose of `passwordDigestor=client` is to improve the security of SCRAM-SHA-1, allowing the creation of new users
224- // without the need to communicate their password to the server.
225- const hash = crypto . createHash ( 'md5' ) ;
226- hash . update ( `${ username } :mongo:${ command . pwd } ` ) ;
227- const digested = hash . digest ( 'hex' ) ;
228- return { digestPassword : false , pwd : digested } ;
239+ return {
240+ digestPassword : false ,
241+ pwd : await computeLegacyHexMD5 ( sp , `${ username } :mongo:${ command . pwd } ` ) ,
242+ } ;
229243 }
230244 return { digestPassword : true } ;
231245}
0 commit comments