Releases: openMF/mifos-passcode-cmp
Releases · openMF/mifos-passcode-cmp
2.2.0
What's Changed
- Decouple biometrics and passcode libraries by @TheKalpeshPawar in #75
- Update GitHub Actions workflow names for clarity. by @TheKalpeshPawar in #76
Full decoupling of the passcode and biometrics libraries. Neither library imports the other; PasscodeManager has no knowledge of external authenticators, and the biometrics library owns the registration-data lifecycle internally.
Breaking Changes
Passcode Library — fully biometrics-agnostic:
PasscodeManagermethods removed:disableExternalAuth(),notifyExternalAuthSuccess(),setExternalAuthEnabled().PasscodeManagerconstructor now takes onlyadapter— theisExternalAuthEnabled: Booleanparameter is gone.PasscodeState.isExternalAuthEnabledfield removed.PasscodeResult.ExternalAuthDisabledcase removed.PasscodeStep.DisableExternalAuthcase removed.PasscodeStorageAdapter: the three deprecated methodssaveRegistrationData(),loadRegistrationData(),deleteRegistrationData()are removed entirely — useBiometricStorageAdapterfrom the biometrics library instead.PasscodeScreennow acceptsisExternalAuthEnabled: Booleanas a direct parameter (caller-controlled) instead of reading it fromPasscodeState.
Biometrics Library — owns registration-data lifecycle:
PlatformAuthenticationProviderconstructor now requiresPlatformAuthenticator+BiometricStorageAdapter(previously took an optionalactivity: Any?).PlatformAuthenticationProvider.onAuthenticatorClick()no longer acceptssavedRegistrationData— the stored blob is loaded internally from the adapter.- Composition local renamed:
PlatformAuthenticatorLocalCompositionProvider→PlatformAuthenticatorCompositionProvider. It now requires aBiometricStorageAdapterparameter.
New Features
- Automatic registration-data persistence.
registerUser()saves on success;onAuthenticatorClick()loads on demand; newunregister()clears. Consumers no longer callBiometricStorageAdapter.saveRegistrationData/loadRegistrationData/deleteRegistrationDatadirectly. isRegistered: StateFlow<Boolean>onPlatformAuthenticationProvider. Observe registration state reactively and drive UI from it.unregister()suspend function onPlatformAuthenticationProvider— clears the stored blob and flipsisRegisteredtofalse.
Fixes
- Windows/WebAuthn decode bug.
onAuthenticatorClick()previously fell back to an empty string when no registration blob was stored, which could trigger a WebAuthn decode error on Windows/Desktop and misreport asUserNotRegistered. It now short-circuits cleanly toAuthenticationResult.UserNotRegisteredwhen no blob exists. Android behaviour is unchanged — Android's empty-string-on-success marker still passes through correctly.
Migration
Passcode library:
Before:
// DI
PasscodeManager(
adapter = get(),
isExternalAuthEnabled = biometricAdapter.loadRegistrationData() != null,
)
// Biometric unlock — went through the manager
passcodeManager.notifyExternalAuthSuccess()
// Enable / disable external auth
passcodeManager.setExternalAuthEnabled(true)
passcodeManager.disableExternalAuth()
// Screen
PasscodeScreen(
passcodeManager = passcodeManager,
onResult = { result ->
when (result) {
PasscodeResult.ExternalAuthDisabled -> popBack()
// other cases
}
},
)After:
// DI — no external-auth flag at construction
PasscodeManager(adapter = get())
// Biometric unlock — handle in your app, never routed through PasscodeManager
// (use a separate callback from your biometric button; the passcode library no
// longer has a "mark verified from outside" API)
// Enable / disable — the biometrics library owns this state
authProvider.registerUser(...) // sets isRegistered = true automatically
authProvider.unregister() // sets isRegistered = false automatically
// Screen — pass isExternalAuthEnabled explicitly, drive from whatever state you own
val isRegistered by authProvider.isRegistered.collectAsState()
PasscodeScreen(
passcodeManager = passcodeManager,
onResult = { result ->
when (result) {
PasscodeResult.Verified -> ...
PasscodeResult.Created -> ...
PasscodeResult.Changed -> ...
PasscodeResult.Forgotten -> ...
PasscodeResult.Rejected -> ...
// ExternalAuthDisabled no longer exists
}
},
isExternalAuthEnabled = isRegistered,
externalAuthButton = { modifier -> YourBiometricButton(modifier) },
)Biometrics library:
Before:
@Composable
fun App() {
PlatformAuthenticatorLocalCompositionProvider {
MaterialTheme { /* ... */ }
}
}
// Register — consumer saves the blob
val result = authProvider.registerUser(...)
if (result is RegistrationResult.Success) {
biometricStorageAdapter.saveRegistrationData(result.message)
}
// Authenticate — consumer loads the blob
val blob = biometricStorageAdapter.loadRegistrationData() ?: ""
val result = authProvider.onAuthenticatorClick(appName, blob)
// Unregister — consumer deletes the blob
biometricStorageAdapter.deleteRegistrationData()After:
@Composable
fun App() {
val biometricStorageAdapter = koinInject<BiometricStorageAdapter>()
PlatformAuthenticatorCompositionProvider(biometricStorageAdapter) {
MaterialTheme { /* ... */ }
}
}
// Register — save happens internally
authProvider.registerUser(...)
// Authenticate — load happens internally; no registration-data argument
val result = authProvider.onAuthenticatorClick(appName)
// Unregister — clears storage and flips isRegistered
authProvider.unregister()Notes
- Bridging the two libraries is now the consumer's responsibility — typically via a small wrapper composable that passes the biometrics library's
isRegisteredstate intoPasscodeScreenand renders the biometric button. See the sample app (cmp-sample-shared) for a working reference:PasscodeScreenWithBiometrics.kt. - Both library READMEs have been rewritten to describe only their own library; cross-library integration examples live in the sample app.
2.1.0
What's Changed
- Biometrics button on passcode screen by @TheKalpeshPawar in #67
- Handel cancellation of bio metric prompt by user && Critical bug fixes by @TheKalpeshPawar in #70
- Simplify PasscodeManager API and decouple passcode/biometrics libraries by @TheKalpeshPawar in #73
Full Changelog: 2.0.5...breaking-changes
Breaking Changes
PasscodeManager API overhaul:
- Constructor no longer takes
CoroutineScope. Now takesisExternalAuthEnabled: Booleanparameter. PasscodeActionsealed interface removed. Use direct methods instead:passcodeManager.changePasscode()passcodeManager.logOut()passcodeManager.disableExternalAuth()passcodeManager.notifyExternalAuthSuccess()passcodeManager.setExternalAuthEnabled(enabled)
PasscodeEventsealed interface removed. UsePasscodeResultviaonResultcallback.trySendAction()removed.rememberPasscodeManager()removed. Scope as a singleton via your DI framework..initialize()removed. Initialization happens in constructor.
PasscodeScreen signature changed:
- 7 individual callbacks (
onPasscodeConfirm,onForgotButton,onPasscodeCreation,onPasscodeChanged,onPasscodeRejected,onDisableExternalAuth,onExternalAuthError) replaced by singleonResult: (PasscodeResult) -> Unit. biometricButtonparameter renamed toexternalAuthButton.
PasscodeStorageAdapter:
saveRegistrationData(),loadRegistrationData(),deleteRegistrationData()are deprecated. UseBiometricStorageAdapterfrom the biometrics library instead.
Naming:
- All
Biometric*names inPasscodeAction,PasscodeEvent,PasscodeStep,PasscodeStaterenamed toExternal*equivalents (e.g.isBiometricEnabled->isExternalAuthEnabled,DisableBiometrics->DisableExternalAuth).
Migration
Before:
// Constructor
PasscodeManager(adapter, MainScope()).initialize(isExternalAuthEnabled)
// Sending actions
passcodeManager.trySendAction(PasscodeAction.ChangePasscode)
passcodeManager.trySendAction(PasscodeAction.BiometricUnlockSuccess)
// PasscodeScreen
PasscodeScreen(
passcodeManager = passcodeManager,
onPasscodeConfirm = { navigate(Home) },
onPasscodeCreation = { navigate(Setup) },
onForgotButton = { navigate(Login) },
// ... 4 more callbacks
)After:
// Constructor
PasscodeManager(adapter, isExternalAuthEnabled)
// Direct methods
passcodeManager.changePasscode()
passcodeManager.notifyExternalAuthSuccess()
// PasscodeScreen
PasscodeScreen(
passcodeManager = passcodeManager,
onResult = { result ->
when (result) {
PasscodeResult.Verified -> navigate(Home)
PasscodeResult.Created -> navigate(Setup)
PasscodeResult.Forgotten -> navigate(Login)
PasscodeResult.Changed -> navigate(Home)
PasscodeResult.ExternalAuthDisabled -> popBack()
PasscodeResult.Rejected -> { }
}
},
)Biometrics Library:
AuthenticationResult.UserCancelledadded —whenblocks onAuthenticationResultmust handle this new variant.RegistrationResult.UserCancelledadded —whenblocks onRegistrationResultmust handle this new variant.
passcode-2.0.5, biometrics-2.0.4
What's Changed
- (chore) kotlin and cmp versiona downgrade by @TheKalpeshPawar in #66
Full Changelog: passcode-v2.0.4...2.0.5
passcode-2.0.4
What's Changed
- Removed skip passcode and updated documentation by @TheKalpeshPawar in #65
Full Changelog: 2.0.3...passcode-v2.0.4
2.0.3
What's Changed
- Bug Fix: Fix change passcode and logout functionality by @TheKalpeshPawar in #64
Full Changelog: Release...2.0.3
2.0.0
What's Changed
- Created first README.md by @TheKalpeshPawar in #14
- Refactor App Lock Architecture: Decouple Datastore, Separate Auth Screens, and Implement App Lock Selection by @TheKalpeshPawar in #16
- Removed TargetFormat.AppImage by @TheKalpeshPawar in #18
- Fixed icons and text alignment in AuthOption card of ChooseAuthOption Screen. by @TheKalpeshPawar in #19
- Fragment activity is now provided by CompositionLocal by @TheKalpeshPawar in #21
- Migrated old MifosPasscode impl from Mifos Pay here with some required changes. by @TheKalpeshPawar in #22
- Reusing the original passcode impl of this library. by @TheKalpeshPawar in #23
- Fixed "failed to launch jvm" issue for desktop and resolved some import issues that were created because of moving files. by @TheKalpeshPawar in #24
- Clean the library and provided abstaract implementation for everything. by @TheKalpeshPawar in #28
- Fixed some ui flow issues in sample app and improved it. by @TheKalpeshPawar in #29
- Some Ui changes in the DeviceAuthScreen by @TheKalpeshPawar in #30
- Fix: Desktop app not working by @TheKalpeshPawar in #31
- Added jsMain as a new source set sample app. It is working. by @TheKalpeshPawar in #32
- Fix: Try again was showing only once even for multiple failed passcode attempts by @TheKalpeshPawar in #33
- Improved Support: The device specific authentication is now supported on API <=29 for android. by @TheKalpeshPawar in #34
- Updating readme by @TheKalpeshPawar in #37
- Readme Update by @TheKalpeshPawar in #38
- Feature: Support for platform authentication on Windows. by @TheKalpeshPawar in #36
- Add iOS build support for Compose Multiplatform module by @HekmatullahAmin in #41
- Implement biometric authentication support for iOS by @HekmatullahAmin in #42
- Feture: Allow user to select passcode length, 4&6 digit. by @TheKalpeshPawar in #43
- Update LICENSE by @DavidH-1 in #48
- Modulaized the project. by @TheKalpeshPawar in #49
- Fix library by @TheKalpeshPawar in #51
- Removed the sample application module. by @TheKalpeshPawar in #52
- Remove unnecessary modules by @TheKalpeshPawar in #53
- Removed
DESIGNSYSTEM_ANALYSIS.mdand refactoredlibs.versions.toml. by @TheKalpeshPawar in #54 - Add build logic by @TheKalpeshPawar in #55
- Reimplemented the whole passcode handeling logic implemented and the ability to change passcode. by @TheKalpeshPawar in #56
- Getting library ready to publish. by @TheKalpeshPawar in #57
New Contributors
- @TheKalpeshPawar made their first contribution in #14
- @HekmatullahAmin made their first contribution in #41
- @DavidH-1 made their first contribution in #48
Full Changelog: 1.0.5...2.00
1.0.5: Merge pull request #4 from openMF/feat_sample
Feature sample compose multiplatform project
1.0.4
Updated publish.yml