Improve biometric lock security and hide it on tv

This commit is contained in:
IndusAryan 2024-03-17 01:51:19 +05:30
parent 638cc4fee9
commit 6f1b0d297c
6 changed files with 84 additions and 34 deletions

View file

@ -154,7 +154,7 @@ repositories {
dependencies { dependencies {
// Testing // Testing
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
testImplementation("org.json:json:20231013") testImplementation("org.json:json:20240303")
androidTestImplementation("androidx.test:core") androidTestImplementation("androidx.test:core")
implementation("androidx.test.ext:junit-ktx:1.1.5") implementation("androidx.test.ext:junit-ktx:1.1.5")
androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.ext:junit:1.1.5")
@ -163,10 +163,10 @@ dependencies {
// Android Core & Lifecycle // Android Core & Lifecycle
implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.navigation:navigation-ui-ktx:2.7.6") implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0") implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0") implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
implementation("androidx.navigation:navigation-fragment-ktx:2.7.6") implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
// Design & UI // Design & UI
implementation("jp.wasabeef:glide-transformations:4.3.0") implementation("jp.wasabeef:glide-transformations:4.3.0")

View file

@ -1,6 +1,7 @@
package com.lagradost.cloudstream3 package com.lagradost.cloudstream3
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.app.Activity
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -62,9 +63,11 @@ import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
import com.lagradost.cloudstream3.APIHolder.initAll import com.lagradost.cloudstream3.APIHolder.initAll
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
import com.lagradost.cloudstream3.AcraApplication.Companion.context
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.CommonActivity.activity
import com.lagradost.cloudstream3.CommonActivity.loadThemes import com.lagradost.cloudstream3.CommonActivity.loadThemes
import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
@ -135,6 +138,7 @@ import com.lagradost.cloudstream3.utils.BackupUtils.backup
import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup import com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup
import com.lagradost.cloudstream3.utils.BiometricAuthenticator import com.lagradost.cloudstream3.utils.BiometricAuthenticator
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.Coroutines.main
@ -1226,10 +1230,9 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
changeStatusBarState(isEmulatorSettings()) changeStatusBarState(isEmulatorSettings())
/** Biometric stuff for users without accounts **/ /** Biometric stuff for users without accounts **/
val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_key), false)
val noAccounts = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false) || accounts.count() <= 1 val noAccounts = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false) || accounts.count() <= 1
if (isTruePhone() && authEnabled && noAccounts) { if (isTruePhone() && isAuthEnabled(this) && noAccounts) {
if (deviceHasPasswordPinLock(this)) { if (deviceHasPasswordPinLock(this)) {
startBiometricAuthentication(this, R.string.biometric_authentication_title, false) startBiometricAuthentication(this, R.string.biometric_authentication_title, false)
@ -1787,6 +1790,14 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricAu
binding?.navHostFragment?.isInvisible = false binding?.navHostFragment?.isInvisible = false
} }
override fun onAuthenticationError() {
try {
finish()
}
catch (e:Exception) {
print(e)
}
}
private var backPressedCallback: OnBackPressedCallback? = null private var backPressedCallback: OnBackPressedCallback? = null
private fun attachBackPressedCallback() { private fun attachBackPressedCallback() {

View file

@ -22,6 +22,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueP
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.utils.BiometricAuthenticator import com.lagradost.cloudstream3.utils.BiometricAuthenticator
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock import com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication import com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication
import com.lagradost.cloudstream3.utils.DataStoreHelper.accounts import com.lagradost.cloudstream3.utils.DataStoreHelper.accounts
import com.lagradost.cloudstream3.utils.DataStoreHelper.selectedKeyIndex import com.lagradost.cloudstream3.utils.DataStoreHelper.selectedKeyIndex
@ -46,7 +47,6 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
) )
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_key), false)
val skipStartup = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false val skipStartup = settingsManager.getBoolean(getString(R.string.skip_startup_account_select_key), false
) || accounts.count() <= 1 ) || accounts.count() <= 1
@ -54,7 +54,7 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
fun askBiometricAuth() { fun askBiometricAuth() {
if (isTruePhone() && authEnabled) { if (isTruePhone() && isAuthEnabled(this)) {
if (deviceHasPasswordPinLock(this)) { if (deviceHasPasswordPinLock(this)) {
startBiometricAuthentication( startBiometricAuthentication(
this, this,
@ -187,4 +187,8 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
override fun onAuthenticationSuccess() { override fun onAuthenticationSuccess() {
Log.i(BiometricAuthenticator.TAG,"Authentication successful in AccountSelectActivity") Log.i(BiometricAuthenticator.TAG,"Authentication successful in AccountSelectActivity")
} }
override fun onAuthenticationError() {
finish()
}
} }

View file

@ -12,6 +12,7 @@ import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.preference.SwitchPreferenceCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser
import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
@ -30,19 +31,22 @@ import com.lagradost.cloudstream3.syncproviders.AuthAPI
import com.lagradost.cloudstream3.syncproviders.InAppAuthAPI import com.lagradost.cloudstream3.syncproviders.InAppAuthAPI
import com.lagradost.cloudstream3.syncproviders.OAuth2API import com.lagradost.cloudstream3.syncproviders.OAuth2API
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTruePhone
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
import com.lagradost.cloudstream3.utils.AppUtils.html import com.lagradost.cloudstream3.utils.AppUtils.html
import com.lagradost.cloudstream3.utils.BackupUtils import com.lagradost.cloudstream3.utils.BackupUtils
import com.lagradost.cloudstream3.utils.BiometricAuthenticator
import com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogText import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogText
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.UIHelper.setImage
class SettingsAccount : PreferenceFragmentCompat() { class SettingsAccount : PreferenceFragmentCompat(),BiometricAuthenticator.BiometricAuthCallback {
companion object { companion object {
/** Used by nginx plugin too */ /** Used by nginx plugin too */
fun showLoginInfo( fun showLoginInfo(
@ -250,6 +254,31 @@ class SettingsAccount : PreferenceFragmentCompat() {
} }
} }
private fun updateAuthPreference(enabled: Boolean) {
val biometricKey = getString(R.string.biometric_key)
PreferenceManager.getDefaultSharedPreferences(context ?: requireContext()).edit()
.putBoolean(biometricKey, enabled).apply()
findPreference<SwitchPreferenceCompat>(biometricKey)?.isChecked = enabled
}
override fun onAuthenticationError() {
updateAuthPreference(!isAuthEnabled(context ?: requireContext()))
}
override fun onAuthenticationSuccess() {
if (isAuthEnabled(context?: return)) {
updateAuthPreference(true)
BackupUtils.backup(activity)
activity?.showBottomDialogText(
getString(R.string.biometric_setting),
getString(R.string.biometric_warning).html()
) { onDialogDismissedEvent }
} else {
updateAuthPreference(false)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setUpToolbar(R.string.category_account) setUpToolbar(R.string.category_account)
@ -260,23 +289,27 @@ class SettingsAccount : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard() hideKeyboard()
setPreferencesFromResource(R.xml.settings_account, rootKey) setPreferencesFromResource(R.xml.settings_account, rootKey)
// hide preference on tvs and emulators
if (!isTruePhone()) {
getPref(R.string.biometric_key)?.isVisible = false
}
getPref(R.string.biometric_key)?.setOnPreferenceClickListener { getPref(R.string.biometric_key)?.setOnPreferenceClickListener {
val authEnabled = PreferenceManager.getDefaultSharedPreferences( val ctx = context ?: return@setOnPreferenceClickListener false
context ?: return@setOnPreferenceClickListener false
)
.getBoolean(getString(R.string.biometric_key), false)
if (authEnabled) { if (BiometricAuthenticator.deviceHasPasswordPinLock(ctx)) {
BackupUtils.backup(activity) BiometricAuthenticator.startBiometricAuthentication(
val title = activity?.getString(R.string.biometric_setting) activity?: requireActivity(),
val warning = activity?.getString(R.string.biometric_warning) R.string.biometric_authentication_title,
activity?.showBottomDialogText( false
title as String, )
warning.html() BiometricAuthenticator.promptInfo?.let {
) { onDialogDismissedEvent } BiometricAuthenticator.authCallback = this
BiometricAuthenticator.biometricPrompt?.authenticate(it)
} }
true }
false
} }
val syncApis = val syncApis =

View file

@ -12,7 +12,9 @@ import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK
import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL import androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL
import androidx.biometric.BiometricPrompt import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.getString
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import androidx.preference.PreferenceManager
import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
@ -21,7 +23,6 @@ object BiometricAuthenticator {
private const val MAX_FAILED_ATTEMPTS = 3 private const val MAX_FAILED_ATTEMPTS = 3
private var failedAttempts = 0 private var failedAttempts = 0
const val TAG = "cs3Auth" const val TAG = "cs3Auth"
private var biometricManager: BiometricManager? = null private var biometricManager: BiometricManager? = null
var biometricPrompt: BiometricPrompt? = null var biometricPrompt: BiometricPrompt? = null
var promptInfo: BiometricPrompt.PromptInfo? = null var promptInfo: BiometricPrompt.PromptInfo? = null
@ -42,15 +43,8 @@ object BiometricAuthenticator {
super.onAuthenticationError(errorCode, errString) super.onAuthenticationError(errorCode, errString)
showToast("$errString") showToast("$errString")
Log.e(TAG, "$errorCode") Log.e(TAG, "$errorCode")
failedAttempts++ authCallback?.onAuthenticationError()
//activity.finish()
if (failedAttempts >= MAX_FAILED_ATTEMPTS) {
failedAttempts = 0
activity.finish()
} else {
failedAttempts = 0
activity.finish()
}
} }
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
@ -153,7 +147,7 @@ object BiometricAuthenticator {
// function to start authentication in any fragment or activity // function to start authentication in any fragment or activity
fun startBiometricAuthentication(activity: Activity, title: Int, setDeviceCred: Boolean) { fun startBiometricAuthentication(activity: Activity, title: Int, setDeviceCred: Boolean) {
initializeBiometrics(activity) initializeBiometrics(activity)
authCallback = activity as? BiometricAuthCallback
if (isBiometricHardWareAvailable()) { if (isBiometricHardWareAvailable()) {
authCallback = activity as? BiometricAuthCallback authCallback = activity as? BiometricAuthCallback
authenticationDialog(activity, title, setDeviceCred) authenticationDialog(activity, title, setDeviceCred)
@ -171,7 +165,15 @@ object BiometricAuthenticator {
} }
} }
fun isAuthEnabled(ctx: Context):Boolean {
return ctx.let {
PreferenceManager.getDefaultSharedPreferences(ctx)
.getBoolean(getString(ctx, R.string.biometric_key), false)
}
}
interface BiometricAuthCallback { interface BiometricAuthCallback {
fun onAuthenticationSuccess() fun onAuthenticationSuccess()
fun onAuthenticationError()
} }
} }

View file

@ -249,7 +249,7 @@
<string name="search">Search</string> <string name="search">Search</string>
<string name="library">Library</string> <string name="library">Library</string>
<string name="category_account">Accounts and Security</string> <string name="category_account">Accounts and Security</string>
<string name="category_updates">Updates and backup</string> <string name="category_updates">Updates and Backup</string>
<string name="settings_info">Info</string> <string name="settings_info">Info</string>
<string name="advanced_search">Advanced Search</string> <string name="advanced_search">Advanced Search</string>
<string name="advanced_search_des">Gives you the search results separated by provider</string> <string name="advanced_search_des">Gives you the search results separated by provider</string>
@ -611,7 +611,7 @@
<string name="tracks">Tracks</string> <string name="tracks">Tracks</string>
<string name="audio_tracks">Audio tracks</string> <string name="audio_tracks">Audio tracks</string>
<string name="video_tracks">Video tracks</string> <string name="video_tracks">Video tracks</string>
<string name="apply_on_restart">Apply on Restart</string> <string name="apply_on_restart">Restart the app to see changes.</string>
<string name="restart">Restart</string> <string name="restart">Restart</string>
<string name="stop">Stop</string> <string name="stop">Stop</string>
<string name="safe_mode_title">Safe mode on</string> <string name="safe_mode_title">Safe mode on</string>