@@ -1932,6 +1932,18 @@ export class BitGoAPI implements BitGoBase {
19321932 password : this . calculateHMAC ( user . username , newPassword ) ,
19331933 } ;
19341934
1935+ // Check if batching flow is enabled
1936+ const batchingFlowCheck = await this . get ( this . url ( '/user/checkBatchingPasswordFlow' , 2 ) ) . result ( ) ;
1937+
1938+ if ( batchingFlowCheck . isBatchingFlowEnabled ) {
1939+ await this . processKeychainPasswordUpdatesInBatches (
1940+ updatePasswordParams . keychains ,
1941+ updatePasswordParams . v2_keychains ,
1942+ batchingFlowCheck . noOfBatches ,
1943+ 3
1944+ ) ;
1945+ }
1946+
19351947 return this . post ( this . url ( '/user/changepassword' ) ) . send ( updatePasswordParams ) . result ( ) ;
19361948 }
19371949
@@ -2173,4 +2185,63 @@ export class BitGoAPI implements BitGoBase {
21732185 const result = await req ;
21742186 return result . body ;
21752187 }
2188+
2189+ /**
2190+ * Process keychain password updates in batches with retry logic
2191+ * @param keychains - The v1 keychains to update
2192+ * @param v2Keychains - The v2 keychains to update
2193+ * @param noOfBatches - Number of batches to split the keychains into
2194+ * @param maxRetries - Maximum number of retries per batch
2195+ * @private
2196+ */
2197+ private async processKeychainPasswordUpdatesInBatches (
2198+ keychains : Record < string , string > ,
2199+ v2Keychains : Record < string , string > ,
2200+ noOfBatches : number ,
2201+ maxRetries : number
2202+ ) : Promise < void > {
2203+ // Split keychains into batches
2204+ const v1KeychainEntries = Object . entries ( keychains ) ;
2205+ const v2KeychainEntries = Object . entries ( v2Keychains ) ;
2206+
2207+ const v1BatchSize = Math . ceil ( v1KeychainEntries . length / noOfBatches ) ;
2208+ const v2BatchSize = Math . ceil ( v2KeychainEntries . length / noOfBatches ) ;
2209+
2210+ // Call batching API for each batch with retry logic
2211+ for ( let i = 0 ; i < noOfBatches ; i ++ ) {
2212+ const v1Batch = Object . fromEntries ( v1KeychainEntries . slice ( i * v1BatchSize , ( i + 1 ) * v1BatchSize ) ) ;
2213+ const v2Batch = Object . fromEntries ( v2KeychainEntries . slice ( i * v2BatchSize , ( i + 1 ) * v2BatchSize ) ) ;
2214+
2215+ let retryCount = 0 ;
2216+ let success = false ;
2217+
2218+ while ( retryCount < maxRetries && ! success ) {
2219+ try {
2220+ const response = await this . put ( this . url ( '/user/keychains' , 2 ) )
2221+ . send ( {
2222+ keychains : v1Batch ,
2223+ v2_keychains : v2Batch ,
2224+ } )
2225+ . result ( ) ;
2226+
2227+ // Check if there are any failed keychains in the response
2228+ const hasFailed =
2229+ ( response . failed ?. v1 && Object . keys ( response . failed . v1 ) . length > 0 ) ||
2230+ ( response . failed ?. v2 && Object . keys ( response . failed . v2 ) . length > 0 ) ;
2231+
2232+ if ( hasFailed ) {
2233+ throw new Error ( `Batch ${ i + 1 } had failed keychains: ${ JSON . stringify ( response . failed ) } ` ) ;
2234+ }
2235+
2236+ success = true ;
2237+ } catch ( error ) {
2238+ retryCount ++ ;
2239+
2240+ if ( retryCount >= maxRetries ) {
2241+ throw new Error ( `Batch ${ i + 1 } failed after ${ maxRetries } retries: ${ error . message } ` ) ;
2242+ }
2243+ }
2244+ }
2245+ }
2246+ }
21762247}
0 commit comments