diff --git a/CHANGELOG.md b/CHANGELOG.md index 7db57f8dbf6..e902ae21ecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Table of Contents + +* [Changelog for 4.8.4](#changelog-for-owncloud-android-client-484-2026-08-31) * [Changelog for 4.8.3](#changelog-for-owncloud-android-client-483-2026-07-21) * [Changelog for 4.8.2](#changelog-for-owncloud-android-client-482-2026-07-01) * [Changelog for 4.8.1](#changelog-for-owncloud-android-client-481-2026-06-09) @@ -34,6 +36,28 @@ * [Changelog for 2.18.1](#changelog-for-owncloud-android-client-2181-2021-07-20) * [Changelog for 2.18.0](#changelog-for-owncloud-android-client-2180-2021-05-24) * [Changelog for 2.17 versions and below](#changelog-for-217-versions-and-below) + +# Changelog for ownCloud Android Client [4.8.4] (2026-08-31) + +The following sections list the changes in ownCloud Android Client 4.8.4 relevant to +ownCloud admins and users. + +[4.8.4]: https://github.com/owncloud/android/compare/v4.8.3...v4.8.4 + +## Summary + +* Security - Prevent bypassing passcode, pattern and biometric lock: [#4958](https://github.com/owncloud/android/issues/4958) + +## Details + +* Security - Prevent bypassing passcode, pattern and biometric lock: [#4958](https://github.com/owncloud/android/issues/4958) + + The back gesture has been prevented from dismissing the lock screen without + validating the passcode, pattern or biometric lock. + + https://github.com/owncloud/android/issues/4958 + https://github.com/owncloud/android/pull/4963 + # Changelog for ownCloud Android Client [4.8.3] (2026-07-21) The following sections list the changes in ownCloud Android Client 4.8.3 relevant to diff --git a/changelog/4.8.4_2026-08-31/4963 b/changelog/4.8.4_2026-08-31/4963 new file mode 100644 index 00000000000..728de185872 --- /dev/null +++ b/changelog/4.8.4_2026-08-31/4963 @@ -0,0 +1,7 @@ +Security: Prevent bypassing passcode, pattern and biometric lock + +The back gesture has been prevented from dismissing the lock screen +without validating the passcode, pattern or biometric lock. + +https://github.com/owncloud/android/issues/4958 +https://github.com/owncloud/android/pull/4963 diff --git a/owncloudApp/build.gradle b/owncloudApp/build.gradle index a8a9a595118..738431de7bc 100644 --- a/owncloudApp/build.gradle +++ b/owncloudApp/build.gradle @@ -100,8 +100,8 @@ android { testInstrumentationRunner "com.owncloud.android.utils.OCTestAndroidJUnitRunner" - versionCode = 48000300 - versionName = "4.8.3" + versionCode = 48000400 + versionName = "4.8.4" buildConfigField "String", gitRemote, "\"" + getGitOriginRemote() + "\"" buildConfigField "String", commitSHA1, "\"" + getLatestGitHash() + "\"" diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/security/passcode/PassCodeActivity.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/security/passcode/PassCodeActivity.kt index a4f53c8c744..cb3157e39b1 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/security/passcode/PassCodeActivity.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/security/passcode/PassCodeActivity.kt @@ -39,6 +39,7 @@ import android.view.View import android.view.WindowManager import android.widget.EditText import android.widget.LinearLayout +import androidx.activity.OnBackPressedCallback import com.owncloud.android.BuildConfig import com.owncloud.android.R import com.owncloud.android.databinding.PasscodeLockActivityBinding @@ -76,6 +77,15 @@ class PassCodeActivity : ToolbarActivity(), NumberKeyboardListener, EnableBiomet private var confirmingPassCode = false private val resultIntent = Intent() + private val onBackPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if ((ACTION_CREATE == intent.action && intent.extras?.getBoolean(EXTRAS_LOCK_ENFORCED) != true) || ACTION_REMOVE == intent.action) { + PassCodeManager.onActivityStopped(this@PassCodeActivity) + finish() + } + } + } + /** * Initializes the activity. * @@ -92,6 +102,8 @@ class PassCodeActivity : ToolbarActivity(), NumberKeyboardListener, EnableBiomet subscribeToViewModel() + onBackPressedDispatcher.addCallback(this, onBackPressedCallback) + _binding = PasscodeLockActivityBinding.inflate(layoutInflater) // protection against screen recording @@ -180,7 +192,7 @@ class PassCodeActivity : ToolbarActivity(), NumberKeyboardListener, EnableBiomet } override fun onOptionsItemSelected(item: MenuItem): Boolean { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } @@ -189,11 +201,6 @@ class PassCodeActivity : ToolbarActivity(), NumberKeyboardListener, EnableBiomet outState.putString(STATE_PASSCODE, passCodeViewModel.passcode.value.orEmpty()) } - override fun onBackPressed() { - PassCodeManager.onActivityStopped(this) - super.onBackPressed() - } - override fun onCreateOptionsMenu(menu: Menu): Boolean = false private fun inflatePasscodeTxtLine() { @@ -382,27 +389,6 @@ class PassCodeActivity : ToolbarActivity(), NumberKeyboardListener, EnableBiomet passCodeEditTexts.first()?.requestFocus() } - /** - * Overrides click on the BACK arrow to correctly cancel ACTION_ENABLE or ACTION_DISABLE, while - * preventing than ACTION_CHECK may be worked around. - * - * @param keyCode Key code of the key that triggered the down event. - * @param event Event triggered. - * @return 'True' when the key event was processed by this method. - */ - override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { - if (keyCode == KeyEvent.KEYCODE_BACK && event.repeatCount == 0) { - if ((ACTION_CREATE == intent.action && - intent.extras?.getBoolean(EXTRAS_LOCK_ENFORCED) != true) || - ACTION_REMOVE == intent.action - ) { - finish() - } // else, do nothing, but report that the key was consumed to stay alive - return true - } - return super.onKeyDown(keyCode, event) - } - /** * Saves the pass code input by the user as the current pass code. */ @@ -462,8 +448,7 @@ class PassCodeActivity : ToolbarActivity(), NumberKeyboardListener, EnableBiomet } KeyEvent.KEYCODE_ESCAPE -> { - PassCodeManager.onActivityStopped(this) - super.onBackPressed() + onBackPressedDispatcher.onBackPressed() true } diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/security/pattern/PatternActivity.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/security/pattern/PatternActivity.kt index f082358071d..41fc1ecb005 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/presentation/security/pattern/PatternActivity.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/security/pattern/PatternActivity.kt @@ -28,11 +28,11 @@ package com.owncloud.android.presentation.security.pattern import android.content.Intent import android.os.Bundle import android.os.SystemClock -import android.view.KeyEvent import android.view.Menu import android.view.MenuItem import android.view.View import android.view.WindowManager +import androidx.activity.OnBackPressedCallback import androidx.core.view.isVisible import com.andrognito.patternlockview.PatternLockView.Dot import com.andrognito.patternlockview.listener.PatternLockViewListener @@ -70,6 +70,16 @@ class PatternActivity : ToolbarActivity(), EnableBiometrics { val resultIntent = Intent() + private val onBackPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (ACTION_REQUEST_WITH_RESULT == intent.action && intent.extras?.getBoolean(EXTRAS_LOCK_ENFORCED) != true || + ACTION_CHECK_WITH_RESULT == intent.action) { + PatternManager.onActivityStopped(this@PatternActivity) + finish() + } + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -77,6 +87,8 @@ class PatternActivity : ToolbarActivity(), EnableBiometrics { window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) } + onBackPressedDispatcher.addCallback(this, onBackPressedCallback) + _binding = PatternLockActivityBinding.inflate(layoutInflater) setContentView(binding.root) @@ -157,15 +169,10 @@ class PatternActivity : ToolbarActivity(), EnableBiometrics { } override fun onOptionsItemSelected(item: MenuItem): Boolean { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } - override fun onBackPressed() { - PatternManager.onActivityStopped(this) - super.onBackPressed() - } - override fun onCreateOptionsMenu(menu: Menu): Boolean = false /** @@ -323,27 +330,6 @@ class PatternActivity : ToolbarActivity(), EnableBiometrics { } } - /** - * Overrides click on the BACK arrow to correctly cancel ACTION_ENABLE or ACTION_DISABLE, while - * preventing than ACTION_CHECK may be worked around. - * - * @param keyCode Key code of the key that triggered the down event. - * @param event Event triggered. - * @return 'True' when the key event was processed by this method. - */ - override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { - if (keyCode == KeyEvent.KEYCODE_BACK && event.repeatCount == 0) { - if (ACTION_REQUEST_WITH_RESULT == intent.action && - intent.extras?.getBoolean(EXTRAS_LOCK_ENFORCED) != true || - ACTION_CHECK_WITH_RESULT == intent.action - ) { - finish() - } // else, do nothing, but report that the key was consumed to stay alive - return true - } - return super.onKeyDown(keyCode, event) - } - override fun onOptionSelected(optionSelected: BiometricStatus) { when (optionSelected) { BiometricStatus.ENABLED_BY_USER -> {