@@ -1932,6 +1932,30 @@ export class BitGoAPI implements BitGoBase {
19321932 password : this . calculateHMAC ( user . username , newPassword ) ,
19331933 } ;
19341934
1935+ // Check if batching flow is enabled
1936+ try {
1937+ const batchingFlowCheck = await this . get ( this . url ( '/user/checkBatchingPasswordFlow' , 2 ) ) . result ( ) ;
1938+
1939+ if ( batchingFlowCheck . isBatchingFlowEnabled ) {
1940+ await this . processKeychainPasswordUpdatesInBatches (
1941+ updatePasswordParams . keychains ,
1942+ updatePasswordParams . v2_keychains ,
1943+ batchingFlowCheck . noOfBatches ,
1944+ 3
1945+ ) ;
1946+ // Call changepassword API without keychains for batching flow
1947+ return this . post ( this . url ( '/user/changepassword' ) )
1948+ . send ( {
1949+ version : updatePasswordParams . version ,
1950+ oldPassword : updatePasswordParams . oldPassword ,
1951+ password : updatePasswordParams . password ,
1952+ } )
1953+ . result ( ) ;
1954+ }
1955+ } catch ( error ) {
1956+ // batching flow check failed
1957+ }
1958+
19351959 return this . post ( this . url ( '/user/changepassword' ) ) . send ( updatePasswordParams ) . result ( ) ;
19361960 }
19371961
@@ -2173,4 +2197,63 @@ export class BitGoAPI implements BitGoBase {
21732197 const result = await req ;
21742198 return result . body ;
21752199 }
2200+
2201+ /**
2202+ * Process keychain password updates in batches with retry logic
2203+ * @param keychains - The v1 keychains to update
2204+ * @param v2Keychains - The v2 keychains to update
2205+ * @param noOfBatches - Number of batches to split the keychains into
2206+ * @param maxRetries - Maximum number of retries per batch
2207+ * @private
2208+ */
2209+ private async processKeychainPasswordUpdatesInBatches (
2210+ keychains : Record < string , string > ,
2211+ v2Keychains : Record < string , string > ,
2212+ noOfBatches : number ,
2213+ maxRetries : number
2214+ ) : Promise < void > {
2215+ // Split keychains into batches
2216+ const v1KeychainEntries = Object . entries ( keychains ) ;
2217+ const v2KeychainEntries = Object . entries ( v2Keychains ) ;
2218+
2219+ const v1BatchSize = Math . ceil ( v1KeychainEntries . length / noOfBatches ) ;
2220+ const v2BatchSize = Math . ceil ( v2KeychainEntries . length / noOfBatches ) ;
2221+
2222+ // Call batching API for each batch with retry logic
2223+ for ( let i = 0 ; i < noOfBatches ; i ++ ) {
2224+ const v1Batch = Object . fromEntries ( v1KeychainEntries . slice ( i * v1BatchSize , ( i + 1 ) * v1BatchSize ) ) ;
2225+ const v2Batch = Object . fromEntries ( v2KeychainEntries . slice ( i * v2BatchSize , ( i + 1 ) * v2BatchSize ) ) ;
2226+
2227+ let retryCount = 0 ;
2228+ let success = false ;
2229+
2230+ while ( retryCount < maxRetries && ! success ) {
2231+ try {
2232+ const response = await this . put ( this . url ( '/user/keychains' , 2 ) )
2233+ . send ( {
2234+ keychains : v1Batch ,
2235+ v2_keychains : v2Batch ,
2236+ } )
2237+ . result ( ) ;
2238+
2239+ // Check if there are any failed keychains in the response
2240+ const hasFailed =
2241+ ( response . failed ?. v1 && Object . keys ( response . failed . v1 ) . length > 0 ) ||
2242+ ( response . failed ?. v2 && Object . keys ( response . failed . v2 ) . length > 0 ) ;
2243+
2244+ if ( hasFailed ) {
2245+ throw new Error ( `Batch ${ i + 1 } had failed keychains: ${ JSON . stringify ( response . failed ) } ` ) ;
2246+ }
2247+
2248+ success = true ;
2249+ } catch ( error ) {
2250+ retryCount ++ ;
2251+
2252+ if ( retryCount >= maxRetries ) {
2253+ throw new Error ( `Batch ${ i + 1 } failed after ${ maxRetries } retries: ${ error . message } ` ) ;
2254+ }
2255+ }
2256+ }
2257+ }
2258+ }
21762259}
0 commit comments