@@ -500,6 +500,9 @@ final class HybridSensitiveInfo : HybridSensitiveInfoSpec() {
500500 return Promise .async(coroutineScope) {
501501 val deps = ensureInitialized()
502502
503+ // Set rotation in progress
504+ deps.keyRotationManager.setRotationInProgress(true )
505+
503506 // Emit started event
504507 rotationEventCallback?.invoke(RotationEvent (
505508 type = " rotation:started" ,
@@ -511,67 +514,82 @@ final class HybridSensitiveInfo : HybridSensitiveInfoSpec() {
511514
512515 val startTime = System .currentTimeMillis()
513516
514- // Generate a new key
515- val newKeyId = System .currentTimeMillis().toString()
516- val success = deps.keyRotationManager.generateNewKey(newKeyId, requiresBiometry = false )
517- if (! success) {
518- rotationEventCallback?.invoke(RotationEvent (
519- type = " rotation:failed" ,
520- timestamp = System .currentTimeMillis().toDouble(),
521- reason = " Failed to generate new key" ,
522- itemsReEncrypted = null ,
523- duration = null
524- ))
525- throw IllegalStateException (" Failed to generate new key for rotation" )
526- }
517+ try {
518+ // Generate a new key
519+ val newKeyId = System .currentTimeMillis().toString()
520+ val success = deps.keyRotationManager.generateNewKey(newKeyId, requiresBiometry = false )
521+ if (! success) {
522+ // Set rotation not in progress on failure
523+ deps.keyRotationManager.setRotationInProgress(false )
524+
525+ rotationEventCallback?.invoke(RotationEvent (
526+ type = " rotation:failed" ,
527+ timestamp = System .currentTimeMillis().toDouble(),
528+ reason = " Failed to generate new key" ,
529+ itemsReEncrypted = null ,
530+ duration = null
531+ ))
532+ throw IllegalStateException (" Failed to generate new key for rotation" )
533+ }
527534
528- // Rotate to the new key
529- val rotateSuccess = deps.keyRotationManager.rotateToNewKey(newKeyId)
530- if (! rotateSuccess) {
531- rotationEventCallback?.invoke(RotationEvent (
532- type = " rotation:failed" ,
533- timestamp = System .currentTimeMillis().toDouble(),
534- reason = " Failed to rotate to new key" ,
535- itemsReEncrypted = null ,
536- duration = null
537- ))
538- throw IllegalStateException (" Failed to rotate to new key" )
539- }
535+ // Rotate to the new key
536+ val rotateSuccess = deps.keyRotationManager.rotateToNewKey(newKeyId)
537+ if (! rotateSuccess) {
538+ // Set rotation not in progress on failure
539+ deps.keyRotationManager.setRotationInProgress(false )
540+
541+ rotationEventCallback?.invoke(RotationEvent (
542+ type = " rotation:failed" ,
543+ timestamp = System .currentTimeMillis().toDouble(),
544+ reason = " Failed to rotate to new key" ,
545+ itemsReEncrypted = null ,
546+ duration = null
547+ ))
548+ throw IllegalStateException (" Failed to rotate to new key" )
549+ }
540550
541- // Perform re-encryption if enabled
542- val preferences = deps.context.getSharedPreferences(
543- " com.sensitiveinfo.keyrotation" ,
544- Context .MODE_PRIVATE
545- )
546- val backgroundReEncryption = preferences.getBoolean(" background_re_encryption" , true )
547- var itemsReEncrypted = 0.0
548- if (backgroundReEncryption) {
549- val result = reEncryptAllItemsImpl(deps, newKeyId)
550- itemsReEncrypted = result.itemsReEncrypted
551- }
551+ // Perform re-encryption if enabled
552+ val preferences = deps.context.getSharedPreferences(
553+ " com.sensitiveinfo.keyrotation" ,
554+ Context .MODE_PRIVATE
555+ )
556+ val backgroundReEncryption = preferences.getBoolean(" background_re_encryption" , true )
557+ var itemsReEncrypted = 0.0
558+ if (backgroundReEncryption) {
559+ val result = reEncryptAllItemsImpl(deps, newKeyId)
560+ itemsReEncrypted = result.itemsReEncrypted
561+ }
552562
553- // Update last rotation timestamp
554- preferences.edit().putLong(" last_rotation_timestamp" , System .currentTimeMillis()).apply ()
563+ // Update last rotation timestamp
564+ preferences.edit().putLong(" last_rotation_timestamp" , System .currentTimeMillis()).apply ()
555565
556- val duration = System .currentTimeMillis() - startTime
566+ val duration = System .currentTimeMillis() - startTime
557567
558- // Emit completed event
559- rotationEventCallback?.invoke(RotationEvent (
560- type = " rotation:completed" ,
561- timestamp = System .currentTimeMillis().toDouble(),
562- reason = request.reason ? : " Manual rotation" ,
563- itemsReEncrypted = itemsReEncrypted,
564- duration = duration.toDouble()
565- ))
568+ // Set rotation not in progress
569+ deps.keyRotationManager.setRotationInProgress(false )
566570
567- // Return result
568- RotationResult (
569- success = true ,
570- newKeyVersion = KeyVersion (id = newKeyId),
571- itemsReEncrypted = itemsReEncrypted,
572- duration = duration.toDouble(),
573- reason = request.reason ? : " Manual rotation"
574- )
571+ // Emit completed event
572+ rotationEventCallback?.invoke(RotationEvent (
573+ type = " rotation:completed" ,
574+ timestamp = System .currentTimeMillis().toDouble(),
575+ reason = request.reason ? : " Manual rotation" ,
576+ itemsReEncrypted = itemsReEncrypted,
577+ duration = duration.toDouble()
578+ ))
579+
580+ // Return result
581+ RotationResult (
582+ success = true ,
583+ newKeyVersion = KeyVersion (id = newKeyId),
584+ itemsReEncrypted = itemsReEncrypted,
585+ duration = duration.toDouble(),
586+ reason = request.reason ? : " Manual rotation"
587+ )
588+ } catch (e: Exception ) {
589+ // Set rotation not in progress on any error
590+ deps.keyRotationManager.setRotationInProgress(false )
591+ throw e
592+ }
575593 }
576594 }
577595
@@ -585,9 +603,10 @@ final class HybridSensitiveInfo : HybridSensitiveInfoSpec() {
585603 val currentKey = deps.keyRotationManager.getCurrentKeyVersion()
586604 val availableVersions = deps.keyRotationManager.getAvailableKeyVersions()
587605 val lastRotationTimestamp = deps.keyRotationManager.getLastRotationTimestamp()
606+ val isRotating = deps.keyRotationManager.isRotationInProgress()
588607
589608 RotationStatus (
590- isRotating = false , // TODO: Track rotation state
609+ isRotating = isRotating,
591610 currentKeyVersion = currentKey?.let { KeyVersion (id = it) },
592611 availableKeyVersions = availableVersions.map { KeyVersion (id = it) }.toTypedArray(),
593612 lastRotationTimestamp = lastRotationTimestamp?.toDouble()
@@ -600,6 +619,8 @@ final class HybridSensitiveInfo : HybridSensitiveInfoSpec() {
600619 */
601620 override fun onRotationEvent (callback : (RotationEvent ) -> Unit ): () -> Unit {
602621 rotationEventCallback = callback
622+ // Also set the biometric change callback to the same callback
623+ dependencies?.keyRotationManager?.setBiometricChangeCallback(callback)
603624 return { rotationEventCallback = null }
604625 }
605626
0 commit comments