add warning and backup

This commit is contained in:
IndusAryan 2024-02-21 21:30:48 +05:30
parent 1369337a72
commit c178355142
7 changed files with 44 additions and 25 deletions

View file

@ -19,6 +19,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import android.widget.Toast import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.IdRes import androidx.annotation.IdRes
@ -1208,26 +1209,21 @@ 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_enabled_key), false) 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() && authEnabled && noAccounts) {
if (deviceHasPasswordPinLock(this)) { if (deviceHasPasswordPinLock(this)) {
startBiometricAuthentication(this, startBiometricAuthentication(this, R.string.biometric_authentication_title, false)
R.string.biometric_authentication_title,
false
)
BiometricAuthenticator.promptInfo?.let { BiometricAuthenticator.promptInfo?.let {
BiometricAuthenticator.biometricPrompt?.authenticate( BiometricAuthenticator.biometricPrompt?.authenticate(it)
it
)
} }
// hide background while authenticating, Sorry moms & dads 🙏 // hide background while authenticating, Sorry moms & dads 🙏
binding?.navHostFragment?.isInvisible = true binding?.navHostFragment?.isInvisible = true
} else { } else {
showToast(R.string.phone_not_secured, Toast.LENGTH_LONG) showToast(R.string.phone_not_secured, LENGTH_LONG)
} }
} }

View file

@ -47,7 +47,7 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
) )
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
val authEnabled = settingsManager.getBoolean(getString(R.string.biometric_enabled_key), false) 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
@ -57,11 +57,8 @@ class AccountSelectActivity : AppCompatActivity(), BiometricAuthenticator.Biomet
if (isTruePhone() && authEnabled) { if (isTruePhone() && authEnabled) {
if (deviceHasPasswordPinLock(this)) { if (deviceHasPasswordPinLock(this)) {
startBiometricAuthentication( startBiometricAuthentication(this, R.string.biometric_authentication_title, false)
this,
R.string.biometric_authentication_title,
false
)
BiometricAuthenticator.promptInfo?.let { BiometricAuthenticator.promptInfo?.let {
BiometricAuthenticator.biometricPrompt?.authenticate(it) BiometricAuthenticator.biometricPrompt?.authenticate(it)
} }

View file

@ -13,6 +13,7 @@ import androidx.fragment.app.FragmentActivity
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
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.showToast import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.databinding.AccountManagmentBinding import com.lagradost.cloudstream3.databinding.AccountManagmentBinding
@ -32,7 +33,10 @@ import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSet
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.BackupUtils
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.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
@ -256,6 +260,19 @@ class SettingsAccount : PreferenceFragmentCompat() {
hideKeyboard() hideKeyboard()
setPreferencesFromResource(R.xml.settings_account, rootKey) setPreferencesFromResource(R.xml.settings_account, rootKey)
getPref(R.string.biometric_key)?.setOnPreferenceClickListener {
BackupUtils.backup(activity)
val title = activity?.getString(R.string.biometric_setting)
val warning = activity?.getString(R.string.biometric_warning)
activity?.showBottomDialogText(
title as String,
warning.html()
) { onDialogDismissedEvent }
true
}
val syncApis = val syncApis =
listOf( listOf(
R.string.mal_key to malApi, R.string.mal_key to malApi,

View file

@ -66,6 +66,7 @@ object BackupUtils {
OPEN_SUBTITLES_USER_KEY, OPEN_SUBTITLES_USER_KEY,
"nginx_user", // Nginx user key "nginx_user", // Nginx user key
"biometric_key" // can lock down users if backup is shared on a incompatible device
) )
/** false if blacklisted key */ /** false if blacklisted key */

View file

@ -5,7 +5,6 @@ import android.app.KeyguardManager
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import android.util.Log import android.util.Log
import android.widget.Toast.LENGTH_SHORT
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricManager import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG import androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG
@ -41,9 +40,10 @@ object BiometricAuthenticator {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString) super.onAuthenticationError(errorCode, errString)
showToast("$errString", LENGTH_SHORT) showToast("$errString")
Log.e(TAG, "$errorCode") Log.e(TAG, "$errorCode")
failedAttempts++ failedAttempts++
if (failedAttempts >= MAX_FAILED_ATTEMPTS) { if (failedAttempts >= MAX_FAILED_ATTEMPTS) {
failedAttempts = 0 failedAttempts = 0
activity.finish() activity.finish()
@ -70,6 +70,7 @@ object BiometricAuthenticator {
}) })
} }
@Suppress("DEPRECATION")
// authentication dialog prompt builder // authentication dialog prompt builder
private fun authenticationDialog( private fun authenticationDialog(
activity: Activity, activity: Activity,
@ -77,6 +78,7 @@ object BiometricAuthenticator {
setDeviceCred: Boolean, setDeviceCred: Boolean,
) { ) {
val description = activity.getString(R.string.biometric_prompt_description) val description = activity.getString(R.string.biometric_prompt_description)
if (setDeviceCred) { if (setDeviceCred) {
// For API level > 30, Newer API setAllowedAuthenticators is used // For API level > 30, Newer API setAllowedAuthenticators is used
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@ -87,17 +89,18 @@ object BiometricAuthenticator {
.setDescription(description) .setDescription(description)
.setAllowedAuthenticators(authFlag) .setAllowedAuthenticators(authFlag)
.build() .build()
} else { } else {
@Suppress("DEPRECATION") // for apis < 30
promptInfo = BiometricPrompt.PromptInfo.Builder() promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle(activity.getString(title)) .setTitle(activity.getString(title))
.setDescription(description) .setDescription(description)
.setDeviceCredentialAllowed(true) .setDeviceCredentialAllowed(true)
.build() .build()
} }
} else { } else {
// fallback for A12+ when both fingerprint & Face unlock is absent but PIN is set // fallback for A12+ when both fingerprint & Face unlock is absent but PIN is set
@Suppress("DEPRECATION")
promptInfo = BiometricPrompt.PromptInfo.Builder() promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle(activity.getString(title)) .setTitle(activity.getString(title))
.setDescription(description) .setDescription(description)
@ -107,9 +110,11 @@ object BiometricAuthenticator {
} }
private fun isBiometricHardWareAvailable(): Boolean { private fun isBiometricHardWareAvailable(): Boolean {
// authentication occurs only when this is true and device is truly capable
var result = false var result = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
when (biometricManager?.canAuthenticate( when (biometricManager?.canAuthenticate(
DEVICE_CREDENTIAL or BIOMETRIC_STRONG or BIOMETRIC_WEAK DEVICE_CREDENTIAL or BIOMETRIC_STRONG or BIOMETRIC_WEAK
)) { )) {
@ -121,6 +126,7 @@ object BiometricAuthenticator {
BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true
BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false
} }
} else { } else {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
when (biometricManager?.canAuthenticate()) { when (biometricManager?.canAuthenticate()) {
@ -137,7 +143,7 @@ object BiometricAuthenticator {
return result return result
} }
// checks if device is secured or not // checks if device is secured i.e has at least some type of lock
fun deviceHasPasswordPinLock(context: Context?): Boolean { fun deviceHasPasswordPinLock(context: Context?): Boolean {
val keyMgr = val keyMgr =
context?.getSystemService(AppCompatActivity.KEYGUARD_SERVICE) as? KeyguardManager context?.getSystemService(AppCompatActivity.KEYGUARD_SERVICE) as? KeyguardManager
@ -160,7 +166,7 @@ object BiometricAuthenticator {
promptInfo?.let { biometricPrompt?.authenticate(it) } promptInfo?.let { biometricPrompt?.authenticate(it) }
} else { } else {
showToast(R.string.biometric_unsupported, LENGTH_SHORT) showToast(R.string.biometric_unsupported)
} }
} }
} }

View file

@ -747,11 +747,13 @@
<!-- For Biometrics --> <!-- For Biometrics -->
<string name="biometric_authentication_title">Unlock CloudStream</string> <string name="biometric_authentication_title">Unlock CloudStream</string>
<string name="biometric_setting">Fingerprint sensor authentication</string> <string name="biometric_setting">Fingerprint/Face unlock authentication</string>
<string name="biometric_enabled_key" translatable="false">biometric_key</string> <string name="biometric_key" translatable="false">biometric_key</string>
<string name="password_pin_authentication_title">Password/PIN Authentication</string> <string name="password_pin_authentication_title">Password/PIN Authentication</string>
<string name="biometric_unsupported">Biometric authentication is not supported on this device</string> <string name="biometric_unsupported">Biometric authentication is not supported on this device</string>
<string name="phone_not_secured">Please disable fingerprint authentication if device has no lock.</string> <string name="phone_not_secured">Please disable fingerprint authentication if device has no lock.</string>
<string name="biometric_prompt_description">This window will close after few failed attempts. You\'ll have to restart the App.</string> <string name="biometric_prompt_description">This window will close after few failed attempts. You\'ll have to restart the App.</string>
<string name="biometric_warning">Your CloudStream data has been backed up now, although probability of this rare case is very low but all
devices behave differently, in case you get locked down from accessing the app in worst case scenario,
Clear the app data wholly and restore the backup. Any inconvenience if arrived is deeply regretted.</string>
</resources> </resources>

View file

@ -24,7 +24,7 @@
android:title="@string/skip_startup_account_select_pref" /> android:title="@string/skip_startup_account_select_pref" />
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:key="@string/biometric_enabled_key" android:key="@string/biometric_key"
android:defaultValue="false" android:defaultValue="false"
android:icon="@drawable/ic_fingerprint" android:icon="@drawable/ic_fingerprint"
android:title="@string/biometric_setting" /> android:title="@string/biometric_setting" />