mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
add warning and backup
This commit is contained in:
parent
1369337a72
commit
c178355142
7 changed files with 44 additions and 25 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue