mirror of
https://github.com/android-password-store/Android-Password-Store
synced 2025-08-31 22:35:17 +00:00
Refactor uses of applicationContext and startActivityForResult (#997)
* Refactor uses of applicationContext and startActivityForResult This commit applies three types of refactoring: 1. Remove context argument from PasswordRepository companion functions by relying on Application.instance. 2. Introduce a sharedPrefs extension function on Context that returns the default SharedPreferences for the applicationContext. 3. Use OpenDocument() and OpenDocumentTree() contracts. * Drop toPasswordItem argument
This commit is contained in:
@@ -15,27 +15,25 @@ import com.github.ajalt.timberkt.Timber.DebugTree
|
|||||||
import com.github.ajalt.timberkt.Timber.plant
|
import com.github.ajalt.timberkt.Timber.plant
|
||||||
import com.zeapo.pwdstore.git.config.setUpBouncyCastleForSshj
|
import com.zeapo.pwdstore.git.config.setUpBouncyCastleForSshj
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
|
|
||||||
@Suppress("Unused")
|
@Suppress("Unused")
|
||||||
class Application : android.app.Application(), SharedPreferences.OnSharedPreferenceChangeListener {
|
class Application : android.app.Application(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
private var prefs: SharedPreferences? = null
|
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
instance = this
|
instance = this
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
if (BuildConfig.ENABLE_DEBUG_FEATURES ||
|
||||||
if (BuildConfig.ENABLE_DEBUG_FEATURES || prefs?.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false) ==
|
sharedPrefs.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false)) {
|
||||||
true) {
|
|
||||||
plant(DebugTree())
|
plant(DebugTree())
|
||||||
}
|
}
|
||||||
prefs?.registerOnSharedPreferenceChangeListener(this)
|
sharedPrefs.registerOnSharedPreferenceChangeListener(this)
|
||||||
setNightMode()
|
setNightMode()
|
||||||
setUpBouncyCastleForSshj()
|
setUpBouncyCastleForSshj()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTerminate() {
|
override fun onTerminate() {
|
||||||
prefs?.unregisterOnSharedPreferenceChangeListener(this)
|
sharedPrefs.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
super.onTerminate()
|
super.onTerminate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +44,7 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setNightMode() {
|
private fun setNightMode() {
|
||||||
AppCompatDelegate.setDefaultNightMode(when (prefs?.getString(PreferenceKeys.APP_THEME, getString(R.string.app_theme_def))) {
|
AppCompatDelegate.setDefaultNightMode(when (sharedPrefs.getString(PreferenceKeys.APP_THEME, getString(R.string.app_theme_def))) {
|
||||||
"light" -> MODE_NIGHT_NO
|
"light" -> MODE_NIGHT_NO
|
||||||
"dark" -> MODE_NIGHT_YES
|
"dark" -> MODE_NIGHT_YES
|
||||||
"follow_system" -> MODE_NIGHT_FOLLOW_SYSTEM
|
"follow_system" -> MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
|
@@ -19,6 +19,7 @@ import androidx.preference.PreferenceManager
|
|||||||
import com.github.ajalt.timberkt.d
|
import com.github.ajalt.timberkt.d
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
import com.zeapo.pwdstore.utils.clipboard
|
import com.zeapo.pwdstore.utils.clipboard
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
@@ -31,7 +32,7 @@ import kotlinx.coroutines.withContext
|
|||||||
class ClipboardService : Service() {
|
class ClipboardService : Service() {
|
||||||
|
|
||||||
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
private val settings: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
|
private val settings: SharedPreferences by lazy { sharedPrefs }
|
||||||
|
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
|
@@ -13,12 +13,13 @@ import androidx.preference.PreferenceManager
|
|||||||
import com.zeapo.pwdstore.crypto.DecryptActivity
|
import com.zeapo.pwdstore.crypto.DecryptActivity
|
||||||
import com.zeapo.pwdstore.utils.BiometricAuthenticator
|
import com.zeapo.pwdstore.utils.BiometricAuthenticator
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
|
|
||||||
class LaunchActivity : AppCompatActivity() {
|
class LaunchActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
val prefs = sharedPrefs
|
||||||
if (prefs.getBoolean(PreferenceKeys.BIOMETRIC_AUTH, false)) {
|
if (prefs.getBoolean(PreferenceKeys.BIOMETRIC_AUTH, false)) {
|
||||||
BiometricAuthenticator.authenticate(this) {
|
BiometricAuthenticator.authenticate(this) {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@@ -58,7 +58,7 @@ class PasswordExportService : Service() {
|
|||||||
*/
|
*/
|
||||||
private fun exportPasswords(targetDirectory: DocumentFile) {
|
private fun exportPasswords(targetDirectory: DocumentFile) {
|
||||||
|
|
||||||
val repositoryDirectory = requireNotNull(PasswordRepository.getRepositoryDirectory(applicationContext))
|
val repositoryDirectory = requireNotNull(PasswordRepository.getRepositoryDirectory())
|
||||||
val sourcePassDir = DocumentFile.fromFile(repositoryDirectory)
|
val sourcePassDir = DocumentFile.fromFile(repositoryDirectory)
|
||||||
|
|
||||||
d { "Copying ${repositoryDirectory.path} to $targetDirectory" }
|
d { "Copying ${repositoryDirectory.path} to $targetDirectory" }
|
||||||
|
@@ -18,7 +18,6 @@ import androidx.activity.result.contract.ActivityResultContracts.StartActivityFo
|
|||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
@@ -33,6 +32,7 @@ import com.zeapo.pwdstore.ui.dialogs.ItemCreationBottomSheet
|
|||||||
import com.zeapo.pwdstore.utils.PasswordItem
|
import com.zeapo.pwdstore.utils.PasswordItem
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import com.zeapo.pwdstore.utils.viewBinding
|
import com.zeapo.pwdstore.utils.viewBinding
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
import me.zhanghai.android.fastscroll.FastScrollerBuilder
|
||||||
@@ -59,7 +59,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
settings = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
settings = requireContext().sharedPrefs
|
||||||
initializePasswordList()
|
initializePasswordList()
|
||||||
binding.fab.setOnClickListener {
|
binding.fab.setOnClickListener {
|
||||||
ItemCreationBottomSheet().show(childFragmentManager, "BOTTOM_SHEET")
|
ItemCreationBottomSheet().show(childFragmentManager, "BOTTOM_SHEET")
|
||||||
@@ -73,7 +73,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initializePasswordList() {
|
private fun initializePasswordList() {
|
||||||
val gitDir = File(PasswordRepository.getRepositoryDirectory(requireContext()), ".git")
|
val gitDir = File(PasswordRepository.getRepositoryDirectory(), ".git")
|
||||||
val hasGitDir = gitDir.exists() && gitDir.isDirectory && (gitDir.listFiles()?.isNotEmpty() == true)
|
val hasGitDir = gitDir.exists() && gitDir.isDirectory && (gitDir.listFiles()?.isNotEmpty() == true)
|
||||||
binding.swipeRefresher.setOnRefreshListener {
|
binding.swipeRefresher.setOnRefreshListener {
|
||||||
if (!hasGitDir) {
|
if (!hasGitDir) {
|
||||||
@@ -180,7 +180,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||||||
// may be called multiple times if the mode is invalidated.
|
// may be called multiple times if the mode is invalidated.
|
||||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||||
menu.findItem(R.id.menu_edit_password).isVisible =
|
menu.findItem(R.id.menu_edit_password).isVisible =
|
||||||
recyclerAdapter.getSelectedItems(requireContext())
|
recyclerAdapter.getSelectedItems()
|
||||||
.all { it.type == PasswordItem.TYPE_CATEGORY }
|
.all { it.type == PasswordItem.TYPE_CATEGORY }
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -189,17 +189,17 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||||
return when (item.itemId) {
|
return when (item.itemId) {
|
||||||
R.id.menu_delete_password -> {
|
R.id.menu_delete_password -> {
|
||||||
requireStore().deletePasswords(recyclerAdapter.getSelectedItems(requireContext()))
|
requireStore().deletePasswords(recyclerAdapter.getSelectedItems())
|
||||||
// Action picked, so close the CAB
|
// Action picked, so close the CAB
|
||||||
mode.finish()
|
mode.finish()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.menu_move_password -> {
|
R.id.menu_move_password -> {
|
||||||
requireStore().movePasswords(recyclerAdapter.getSelectedItems(requireContext()))
|
requireStore().movePasswords(recyclerAdapter.getSelectedItems())
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
R.id.menu_edit_password -> {
|
R.id.menu_edit_password -> {
|
||||||
requireStore().renameCategory(recyclerAdapter.getSelectedItems(requireContext()))
|
requireStore().renameCategory(recyclerAdapter.getSelectedItems())
|
||||||
mode.finish()
|
mode.finish()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@@ -69,6 +69,7 @@ import com.zeapo.pwdstore.utils.contains
|
|||||||
import com.zeapo.pwdstore.utils.isInsideRepository
|
import com.zeapo.pwdstore.utils.isInsideRepository
|
||||||
import com.zeapo.pwdstore.utils.listFilesRecursively
|
import com.zeapo.pwdstore.utils.listFilesRecursively
|
||||||
import com.zeapo.pwdstore.utils.requestInputFocusOnView
|
import com.zeapo.pwdstore.utils.requestInputFocusOnView
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.Character.UnicodeBlock
|
import java.lang.Character.UnicodeBlock
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -83,10 +84,11 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
private lateinit var activity: PasswordStore
|
private lateinit var activity: PasswordStore
|
||||||
private lateinit var searchItem: MenuItem
|
private lateinit var searchItem: MenuItem
|
||||||
private lateinit var searchView: SearchView
|
private lateinit var searchView: SearchView
|
||||||
private lateinit var settings: SharedPreferences
|
|
||||||
private var plist: PasswordFragment? = null
|
private var plist: PasswordFragment? = null
|
||||||
private var shortcutManager: ShortcutManager? = null
|
private var shortcutManager: ShortcutManager? = null
|
||||||
|
|
||||||
|
private val settings by lazy { sharedPrefs }
|
||||||
|
|
||||||
private val model: SearchableRepositoryViewModel by viewModels {
|
private val model: SearchableRepositoryViewModel by viewModels {
|
||||||
ViewModelProvider.AndroidViewModelFactory(application)
|
ViewModelProvider.AndroidViewModelFactory(application)
|
||||||
}
|
}
|
||||||
@@ -119,7 +121,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
dir.exists() &&
|
dir.exists() &&
|
||||||
dir.isDirectory &&
|
dir.isDirectory &&
|
||||||
dir.listFilesRecursively().isNotEmpty() &&
|
dir.listFilesRecursively().isNotEmpty() &&
|
||||||
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
|
getPasswords(dir, getRepositoryDirectory(), sortOrder).isNotEmpty()) {
|
||||||
closeRepository()
|
closeRepository()
|
||||||
checkLocalRepository()
|
checkLocalRepository()
|
||||||
return@registerForActivityResult
|
return@registerForActivityResult
|
||||||
@@ -153,7 +155,6 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
activity = this
|
activity = this
|
||||||
settings = PreferenceManager.getDefaultSharedPreferences(this.applicationContext)
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||||
shortcutManager = getSystemService()
|
shortcutManager = getSystemService()
|
||||||
}
|
}
|
||||||
@@ -209,7 +210,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model.currentDir.observe(this) { dir ->
|
model.currentDir.observe(this) { dir ->
|
||||||
val basePath = getRepositoryDirectory(applicationContext).absoluteFile
|
val basePath = getRepositoryDirectory().absoluteFile
|
||||||
supportActionBar!!.apply {
|
supportActionBar!!.apply {
|
||||||
if (dir != basePath)
|
if (dir != basePath)
|
||||||
title = dir.name
|
title = dir.name
|
||||||
@@ -379,9 +380,9 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
|
|
||||||
private fun createRepository() {
|
private fun createRepository() {
|
||||||
if (!isInitialized) {
|
if (!isInitialized) {
|
||||||
initialize(this)
|
initialize()
|
||||||
}
|
}
|
||||||
val localDir = getRepositoryDirectory(applicationContext)
|
val localDir = getRepositoryDirectory()
|
||||||
try {
|
try {
|
||||||
check(localDir.mkdir()) { "Failed to create directory!" }
|
check(localDir.mkdir()) { "Failed to create directory!" }
|
||||||
createRepository(localDir)
|
createRepository(localDir)
|
||||||
@@ -409,7 +410,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
if (externalRepo && externalRepoPath != null) {
|
if (externalRepo && externalRepoPath != null) {
|
||||||
val dir = File(externalRepoPath)
|
val dir = File(externalRepoPath)
|
||||||
if (dir.exists() && dir.isDirectory &&
|
if (dir.exists() && dir.isDirectory &&
|
||||||
getPasswords(dir, getRepositoryDirectory(this), sortOrder).isNotEmpty()) {
|
getPasswords(dir, getRepositoryDirectory(), sortOrder).isNotEmpty()) {
|
||||||
closeRepository()
|
closeRepository()
|
||||||
checkLocalRepository()
|
checkLocalRepository()
|
||||||
return // if not empty, just show me the passwords!
|
return // if not empty, just show me the passwords!
|
||||||
@@ -449,7 +450,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkLocalRepository() {
|
private fun checkLocalRepository() {
|
||||||
val repo = initialize(this)
|
val repo = initialize()
|
||||||
if (repo == null) {
|
if (repo == null) {
|
||||||
val intent = Intent(activity, UserPreference::class.java)
|
val intent = Intent(activity, UserPreference::class.java)
|
||||||
intent.putExtra("operation", "git_external")
|
intent.putExtra("operation", "git_external")
|
||||||
@@ -459,7 +460,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
}
|
}
|
||||||
}.launch(intent)
|
}.launch(intent)
|
||||||
} else {
|
} else {
|
||||||
checkLocalRepository(getRepositoryDirectory(applicationContext))
|
checkLocalRepository(getRepositoryDirectory())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,7 +473,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
settings.edit { putBoolean(PreferenceKeys.REPO_CHANGED, false) }
|
settings.edit { putBoolean(PreferenceKeys.REPO_CHANGED, false) }
|
||||||
plist = PasswordFragment()
|
plist = PasswordFragment()
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
args.putString(REQUEST_ARG_PATH, getRepositoryDirectory(applicationContext).absolutePath)
|
args.putString(REQUEST_ARG_PATH, getRepositoryDirectory().absolutePath)
|
||||||
|
|
||||||
// if the activity was started from the autofill settings, the
|
// if the activity was started from the autofill settings, the
|
||||||
// intent is to match a clicked pwd with app. pass this to fragment
|
// intent is to match a clicked pwd with app. pass this to fragment
|
||||||
@@ -506,7 +507,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getLastChangedTimestamp(fullPath: String): Long {
|
private fun getLastChangedTimestamp(fullPath: String): Long {
|
||||||
val repoPath = getRepositoryDirectory(this)
|
val repoPath = getRepositoryDirectory()
|
||||||
val repository = getRepository(repoPath)
|
val repository = getRepository(repoPath)
|
||||||
if (repository == null) {
|
if (repository == null) {
|
||||||
d { "getLastChangedTimestamp: No git repository" }
|
d { "getLastChangedTimestamp: No git repository" }
|
||||||
@@ -534,7 +535,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
for (intent in arrayOf(decryptIntent, authDecryptIntent)) {
|
for (intent in arrayOf(decryptIntent, authDecryptIntent)) {
|
||||||
intent.putExtra("NAME", item.toString())
|
intent.putExtra("NAME", item.toString())
|
||||||
intent.putExtra("FILE_PATH", item.file.absolutePath)
|
intent.putExtra("FILE_PATH", item.file.absolutePath)
|
||||||
intent.putExtra("REPO_PATH", getRepositoryDirectory(applicationContext).absolutePath)
|
intent.putExtra("REPO_PATH", getRepositoryDirectory().absolutePath)
|
||||||
intent.putExtra("LAST_CHANGED_TIMESTAMP", getLastChangedTimestamp(item.file.absolutePath))
|
intent.putExtra("LAST_CHANGED_TIMESTAMP", getLastChangedTimestamp(item.file.absolutePath))
|
||||||
}
|
}
|
||||||
// Needs an action to be a shortcut intent
|
// Needs an action to be a shortcut intent
|
||||||
@@ -577,7 +578,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
i { "Adding file to : ${currentDir.absolutePath}" }
|
i { "Adding file to : ${currentDir.absolutePath}" }
|
||||||
val intent = Intent(this, PasswordCreationActivity::class.java)
|
val intent = Intent(this, PasswordCreationActivity::class.java)
|
||||||
intent.putExtra("FILE_PATH", currentDir.absolutePath)
|
intent.putExtra("FILE_PATH", currentDir.absolutePath)
|
||||||
intent.putExtra("REPO_PATH", getRepositoryDirectory(applicationContext).absolutePath)
|
intent.putExtra("REPO_PATH", getRepositoryDirectory().absolutePath)
|
||||||
registerForActivityResult(StartActivityForResult()) { result ->
|
registerForActivityResult(StartActivityForResult()) { result ->
|
||||||
if (result.resultCode == RESULT_OK) {
|
if (result.resultCode == RESULT_OK) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
@@ -623,7 +624,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
refreshPasswordList()
|
refreshPasswordList()
|
||||||
AutofillMatcher.updateMatches(applicationContext, delete = filesToDelete)
|
AutofillMatcher.updateMatches(applicationContext, delete = filesToDelete)
|
||||||
val fmt = selectedItems.joinToString(separator = ", ") { item ->
|
val fmt = selectedItems.joinToString(separator = ", ") { item ->
|
||||||
item.file.toRelativeString(getRepositoryDirectory(this@PasswordStore))
|
item.file.toRelativeString(getRepositoryDirectory())
|
||||||
}
|
}
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
commitChange(
|
commitChange(
|
||||||
@@ -645,7 +646,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
val intentData = result.data ?: return@registerForActivityResult
|
val intentData = result.data ?: return@registerForActivityResult
|
||||||
val filesToMove = requireNotNull(intentData.getStringArrayExtra("Files"))
|
val filesToMove = requireNotNull(intentData.getStringArrayExtra("Files"))
|
||||||
val target = File(requireNotNull(intentData.getStringExtra("SELECTED_FOLDER_PATH")))
|
val target = File(requireNotNull(intentData.getStringExtra("SELECTED_FOLDER_PATH")))
|
||||||
val repositoryPath = getRepositoryDirectory(applicationContext).absolutePath
|
val repositoryPath = getRepositoryDirectory().absolutePath
|
||||||
if (!target.isDirectory) {
|
if (!target.isDirectory) {
|
||||||
e { "Tried moving passwords to a non-existing folder." }
|
e { "Tried moving passwords to a non-existing folder." }
|
||||||
return@registerForActivityResult
|
return@registerForActivityResult
|
||||||
@@ -703,7 +704,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val repoDir = getRepositoryDirectory(applicationContext).absolutePath
|
val repoDir = getRepositoryDirectory().absolutePath
|
||||||
val relativePath = getRelativePath("${target.absolutePath}/", repoDir)
|
val relativePath = getRelativePath("${target.absolutePath}/", repoDir)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
commitChange(
|
commitChange(
|
||||||
@@ -756,7 +757,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
when {
|
when {
|
||||||
newCategoryEditText.text.isNullOrBlank() -> renameCategory(oldCategory, CategoryRenameError.EmptyField)
|
newCategoryEditText.text.isNullOrBlank() -> renameCategory(oldCategory, CategoryRenameError.EmptyField)
|
||||||
newCategory.exists() -> renameCategory(oldCategory, CategoryRenameError.CategoryExists)
|
newCategory.exists() -> renameCategory(oldCategory, CategoryRenameError.CategoryExists)
|
||||||
!isInsideRepository(newCategory) -> renameCategory(oldCategory, CategoryRenameError.DestinationOutsideRepo)
|
!newCategory.isInsideRepository() -> renameCategory(oldCategory, CategoryRenameError.DestinationOutsideRepo)
|
||||||
else -> lifecycleScope.launch(Dispatchers.IO) {
|
else -> lifecycleScope.launch(Dispatchers.IO) {
|
||||||
moveFile(oldCategory.file, newCategory)
|
moveFile(oldCategory.file, newCategory)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
@@ -803,7 +804,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val currentDir: File
|
private val currentDir: File
|
||||||
get() = plist?.currentDir ?: getRepositoryDirectory(applicationContext)
|
get() = plist?.currentDir ?: getRepositoryDirectory()
|
||||||
|
|
||||||
private suspend fun moveFile(source: File, destinationFile: File) {
|
private suspend fun moveFile(source: File, destinationFile: File) {
|
||||||
val sourceDestinationMap = if (source.isDirectory) {
|
val sourceDestinationMap = if (source.isDirectory) {
|
||||||
@@ -887,7 +888,7 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
|
|||||||
fun matchPasswordWithApp(item: PasswordItem) {
|
fun matchPasswordWithApp(item: PasswordItem) {
|
||||||
val path = item.file
|
val path = item.file
|
||||||
.absolutePath
|
.absolutePath
|
||||||
.replace(getRepositoryDirectory(applicationContext).toString() + "/", "")
|
.replace(getRepositoryDirectory().toString() + "/", "")
|
||||||
.replace(".gpg", "")
|
.replace(".gpg", "")
|
||||||
val data = Intent()
|
val data = Intent()
|
||||||
data.putExtra("path", path)
|
data.putExtra("path", path)
|
||||||
|
@@ -5,7 +5,6 @@
|
|||||||
package com.zeapo.pwdstore
|
package com.zeapo.pwdstore
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -31,6 +30,7 @@ import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
|
|||||||
import com.zeapo.pwdstore.utils.PasswordItem
|
import com.zeapo.pwdstore.utils.PasswordItem
|
||||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.Collator
|
import java.text.Collator
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@@ -50,10 +50,10 @@ import kotlinx.coroutines.flow.toList
|
|||||||
import kotlinx.coroutines.yield
|
import kotlinx.coroutines.yield
|
||||||
import me.zhanghai.android.fastscroll.PopupTextProvider
|
import me.zhanghai.android.fastscroll.PopupTextProvider
|
||||||
|
|
||||||
private fun File.toPasswordItem(root: File) = if (isFile)
|
private fun File.toPasswordItem() = if (isFile)
|
||||||
PasswordItem.newPassword(name, this, root)
|
PasswordItem.newPassword(name, this, PasswordRepository.getRepositoryDirectory())
|
||||||
else
|
else
|
||||||
PasswordItem.newCategory(name, this, root)
|
PasswordItem.newCategory(name, this, PasswordRepository.getRepositoryDirectory())
|
||||||
|
|
||||||
private fun PasswordItem.fuzzyMatch(filter: String): Int {
|
private fun PasswordItem.fuzzyMatch(filter: String): Int {
|
||||||
var i = 0
|
var i = 0
|
||||||
@@ -138,8 +138,8 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val root
|
private val root
|
||||||
get() = PasswordRepository.getRepositoryDirectory(getApplication())
|
get() = PasswordRepository.getRepositoryDirectory()
|
||||||
private val settings = PreferenceManager.getDefaultSharedPreferences(getApplication())
|
private val settings by lazy { application.sharedPrefs }
|
||||||
private val showHiddenDirs
|
private val showHiddenDirs
|
||||||
get() = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
|
get() = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
|
||||||
private val defaultSearchMode
|
private val defaultSearchMode
|
||||||
@@ -216,7 +216,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
|
|||||||
val passwordList = when (filterModeToUse) {
|
val passwordList = when (filterModeToUse) {
|
||||||
FilterMode.NoFilter -> {
|
FilterMode.NoFilter -> {
|
||||||
prefilteredResultFlow
|
prefilteredResultFlow
|
||||||
.map { it.toPasswordItem(root) }
|
.map { it.toPasswordItem() }
|
||||||
.toList()
|
.toList()
|
||||||
.sortedWith(itemComparator)
|
.sortedWith(itemComparator)
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
|
|||||||
.filter { absoluteFile ->
|
.filter { absoluteFile ->
|
||||||
regex.containsMatchIn(absoluteFile.relativeTo(root).path)
|
regex.containsMatchIn(absoluteFile.relativeTo(root).path)
|
||||||
}
|
}
|
||||||
.map { it.toPasswordItem(root) }
|
.map { it.toPasswordItem() }
|
||||||
.toList()
|
.toList()
|
||||||
.sortedWith(itemComparator)
|
.sortedWith(itemComparator)
|
||||||
} else {
|
} else {
|
||||||
@@ -238,7 +238,7 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel
|
|||||||
FilterMode.Fuzzy -> {
|
FilterMode.Fuzzy -> {
|
||||||
prefilteredResultFlow
|
prefilteredResultFlow
|
||||||
.map {
|
.map {
|
||||||
val item = it.toPasswordItem(root)
|
val item = it.toPasswordItem()
|
||||||
Pair(item.fuzzyMatch(searchAction.filter), item)
|
Pair(item.fuzzyMatch(searchAction.filter), item)
|
||||||
}
|
}
|
||||||
.filter { it.first > 0 }
|
.filter { it.first > 0 }
|
||||||
@@ -443,10 +443,7 @@ open class SearchableRepositoryAdapter<T : RecyclerView.ViewHolder>(
|
|||||||
private val selectedFiles
|
private val selectedFiles
|
||||||
get() = requireSelectionTracker().selection.map { File(it) }
|
get() = requireSelectionTracker().selection.map { File(it) }
|
||||||
|
|
||||||
fun getSelectedItems(context: Context): List<PasswordItem> {
|
fun getSelectedItems() = selectedFiles.map { it.toPasswordItem() }
|
||||||
val root = PasswordRepository.getRepositoryDirectory(context)
|
|
||||||
return selectedFiles.map { it.toPasswordItem(root) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPositionForFile(file: File) = itemKeyProvider.getPosition(file.absolutePath)
|
fun getPositionForFile(file: File) = itemKeyProvider.getPosition(file.absolutePath)
|
||||||
|
|
||||||
|
@@ -22,7 +22,7 @@ class SelectFolderActivity : AppCompatActivity(R.layout.select_folder_layout) {
|
|||||||
|
|
||||||
passwordList = SelectFolderFragment()
|
passwordList = SelectFolderFragment()
|
||||||
val args = Bundle()
|
val args = Bundle()
|
||||||
args.putString(PasswordStore.REQUEST_ARG_PATH, PasswordRepository.getRepositoryDirectory(applicationContext).absolutePath)
|
args.putString(PasswordStore.REQUEST_ARG_PATH, PasswordRepository.getRepositoryDirectory().absolutePath)
|
||||||
|
|
||||||
passwordList.arguments = args
|
passwordList.arguments = args
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@ package com.zeapo.pwdstore
|
|||||||
|
|
||||||
import android.accessibilityservice.AccessibilityServiceInfo
|
import android.accessibilityservice.AccessibilityServiceInfo
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.pm.ShortcutManager
|
import android.content.pm.ShortcutManager
|
||||||
@@ -20,8 +21,8 @@ import android.text.TextUtils
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.accessibility.AccessibilityManager
|
import android.view.accessibility.AccessibilityManager
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.result.ActivityResult
|
import androidx.activity.result.contract.ActivityResultContracts.OpenDocument
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
import androidx.activity.result.contract.ActivityResultContracts.OpenDocumentTree
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.AppCompatTextView
|
import androidx.appcompat.widget.AppCompatTextView
|
||||||
import androidx.biometric.BiometricManager
|
import androidx.biometric.BiometricManager
|
||||||
@@ -53,6 +54,7 @@ import com.zeapo.pwdstore.utils.PasswordRepository
|
|||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
import com.zeapo.pwdstore.utils.autofillManager
|
import com.zeapo.pwdstore.utils.autofillManager
|
||||||
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
@@ -69,15 +71,15 @@ class UserPreference : AppCompatActivity() {
|
|||||||
private var clearSavedPassPreference: Preference? = null
|
private var clearSavedPassPreference: Preference? = null
|
||||||
private lateinit var autofillDependencies: List<Preference>
|
private lateinit var autofillDependencies: List<Preference>
|
||||||
private lateinit var oreoAutofillDependencies: List<Preference>
|
private lateinit var oreoAutofillDependencies: List<Preference>
|
||||||
private lateinit var callingActivity: UserPreference
|
private lateinit var prefsActivity: UserPreference
|
||||||
private lateinit var sharedPreferences: SharedPreferences
|
private lateinit var sharedPreferences: SharedPreferences
|
||||||
private lateinit var encryptedPreferences: SharedPreferences
|
private lateinit var encryptedPreferences: SharedPreferences
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
callingActivity = requireActivity() as UserPreference
|
prefsActivity = requireActivity() as UserPreference
|
||||||
val context = requireContext()
|
val context = requireContext()
|
||||||
sharedPreferences = preferenceManager.sharedPreferences
|
sharedPreferences = preferenceManager.sharedPreferences
|
||||||
encryptedPreferences = requireActivity().applicationContext.getEncryptedPrefs("git_operation")
|
encryptedPreferences = requireActivity().getEncryptedPrefs("git_operation")
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.preference)
|
addPreferencesFromResource(R.xml.preference)
|
||||||
|
|
||||||
@@ -152,12 +154,12 @@ class UserPreference : AppCompatActivity() {
|
|||||||
appVersionPreference?.summary = "Version: ${BuildConfig.VERSION_NAME}"
|
appVersionPreference?.summary = "Version: ${BuildConfig.VERSION_NAME}"
|
||||||
|
|
||||||
sshKeyPreference?.onPreferenceClickListener = ClickListener {
|
sshKeyPreference?.onPreferenceClickListener = ClickListener {
|
||||||
callingActivity.getSshKey()
|
prefsActivity.getSshKey()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
sshKeygenPreference?.onPreferenceClickListener = ClickListener {
|
sshKeygenPreference?.onPreferenceClickListener = ClickListener {
|
||||||
callingActivity.makeSshKey(true)
|
prefsActivity.makeSshKey(true)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,24 +187,24 @@ class UserPreference : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gitServerPreference?.onPreferenceClickListener = ClickListener {
|
gitServerPreference?.onPreferenceClickListener = ClickListener {
|
||||||
startActivity(Intent(callingActivity, GitServerConfigActivity::class.java))
|
startActivity(Intent(prefsActivity, GitServerConfigActivity::class.java))
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
gitConfigPreference?.onPreferenceClickListener = ClickListener {
|
gitConfigPreference?.onPreferenceClickListener = ClickListener {
|
||||||
startActivity(Intent(callingActivity, GitConfigActivity::class.java))
|
startActivity(Intent(prefsActivity, GitConfigActivity::class.java))
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteRepoPreference?.onPreferenceClickListener = ClickListener {
|
deleteRepoPreference?.onPreferenceClickListener = ClickListener {
|
||||||
val repoDir = PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext)
|
val repoDir = PasswordRepository.getRepositoryDirectory()
|
||||||
MaterialAlertDialogBuilder(callingActivity)
|
MaterialAlertDialogBuilder(prefsActivity)
|
||||||
.setTitle(R.string.pref_dialog_delete_title)
|
.setTitle(R.string.pref_dialog_delete_title)
|
||||||
.setMessage(resources.getString(R.string.dialog_delete_msg, repoDir))
|
.setMessage(resources.getString(R.string.dialog_delete_msg, repoDir))
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
|
.setPositiveButton(R.string.dialog_delete) { dialogInterface, _ ->
|
||||||
try {
|
try {
|
||||||
PasswordRepository.getRepositoryDirectory(callingActivity.applicationContext).deleteRecursively()
|
PasswordRepository.getRepositoryDirectory().deleteRecursively()
|
||||||
PasswordRepository.closeRepository()
|
PasswordRepository.closeRepository()
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
// TODO Handle the different cases of exceptions
|
// TODO Handle the different cases of exceptions
|
||||||
@@ -215,7 +217,7 @@ class UserPreference : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
sharedPreferences.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) }
|
sharedPreferences.edit { putBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false) }
|
||||||
dialogInterface.cancel()
|
dialogInterface.cancel()
|
||||||
callingActivity.finish()
|
prefsActivity.finish()
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } }
|
.setNegativeButton(R.string.dialog_do_not_delete) { dialogInterface, _ -> run { dialogInterface.cancel() } }
|
||||||
.show()
|
.show()
|
||||||
@@ -226,7 +228,7 @@ class UserPreference : AppCompatActivity() {
|
|||||||
selectExternalGitRepositoryPreference?.summary =
|
selectExternalGitRepositoryPreference?.summary =
|
||||||
sharedPreferences.getString(PreferenceKeys.GIT_EXTERNAL_REPO, context.getString(R.string.no_repo_selected))
|
sharedPreferences.getString(PreferenceKeys.GIT_EXTERNAL_REPO, context.getString(R.string.no_repo_selected))
|
||||||
selectExternalGitRepositoryPreference?.onPreferenceClickListener = ClickListener {
|
selectExternalGitRepositoryPreference?.onPreferenceClickListener = ClickListener {
|
||||||
callingActivity.selectExternalGitRepository()
|
prefsActivity.selectExternalGitRepository()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +243,7 @@ class UserPreference : AppCompatActivity() {
|
|||||||
externalGitRepositoryPreference?.onPreferenceChangeListener = resetRepo
|
externalGitRepositoryPreference?.onPreferenceChangeListener = resetRepo
|
||||||
|
|
||||||
autoFillAppsPreference?.onPreferenceClickListener = ClickListener {
|
autoFillAppsPreference?.onPreferenceClickListener = ClickListener {
|
||||||
val intent = Intent(callingActivity, AutofillPreferenceActivity::class.java)
|
val intent = Intent(prefsActivity, AutofillPreferenceActivity::class.java)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -254,7 +256,7 @@ class UserPreference : AppCompatActivity() {
|
|||||||
findPreference<Preference>(PreferenceKeys.EXPORT_PASSWORDS)?.apply {
|
findPreference<Preference>(PreferenceKeys.EXPORT_PASSWORDS)?.apply {
|
||||||
isVisible = sharedPreferences.getBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)
|
isVisible = sharedPreferences.getBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)
|
||||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
callingActivity.exportPasswords()
|
prefsActivity.exportPasswords()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,7 +318,7 @@ class UserPreference : AppCompatActivity() {
|
|||||||
|
|
||||||
val prefCustomXkpwdDictionary = findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
|
val prefCustomXkpwdDictionary = findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
|
||||||
prefCustomXkpwdDictionary?.onPreferenceClickListener = ClickListener {
|
prefCustomXkpwdDictionary?.onPreferenceClickListener = ClickListener {
|
||||||
callingActivity.storeCustomDictionaryPath()
|
prefsActivity.storeCustomDictionaryPath()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
val dictUri = sharedPreferences.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, "")
|
val dictUri = sharedPreferences.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, "")
|
||||||
@@ -361,8 +363,8 @@ class UserPreference : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateAutofillSettings() {
|
private fun updateAutofillSettings() {
|
||||||
val isAccessibilityServiceEnabled = callingActivity.isAccessibilityServiceEnabled
|
val isAccessibilityServiceEnabled = prefsActivity.isAccessibilityServiceEnabled
|
||||||
val isAutofillServiceEnabled = callingActivity.isAutofillServiceEnabled
|
val isAutofillServiceEnabled = prefsActivity.isAutofillServiceEnabled
|
||||||
autoFillEnablePreference?.isChecked =
|
autoFillEnablePreference?.isChecked =
|
||||||
isAccessibilityServiceEnabled || isAutofillServiceEnabled
|
isAccessibilityServiceEnabled || isAutofillServiceEnabled
|
||||||
autofillDependencies.forEach {
|
autofillDependencies.forEach {
|
||||||
@@ -391,16 +393,16 @@ class UserPreference : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onEnableAutofillClick() {
|
private fun onEnableAutofillClick() {
|
||||||
if (callingActivity.isAccessibilityServiceEnabled) {
|
if (prefsActivity.isAccessibilityServiceEnabled) {
|
||||||
startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
|
startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
|
||||||
} else if (callingActivity.isAutofillServiceEnabled) {
|
} else if (prefsActivity.isAutofillServiceEnabled) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
callingActivity.autofillManager!!.disableAutofillServices()
|
prefsActivity.autofillManager!!.disableAutofillServices()
|
||||||
else
|
else
|
||||||
throw IllegalStateException("isAutofillServiceEnabled == true, but Build.VERSION.SDK_INT < Build.VERSION_CODES.O")
|
throw IllegalStateException("isAutofillServiceEnabled == true, but Build.VERSION.SDK_INT < Build.VERSION_CODES.O")
|
||||||
} else {
|
} else {
|
||||||
val enableOreoAutofill = callingActivity.isAutofillServiceSupported
|
val enableOreoAutofill = prefsActivity.isAutofillServiceSupported
|
||||||
MaterialAlertDialogBuilder(callingActivity).run {
|
MaterialAlertDialogBuilder(prefsActivity).run {
|
||||||
setTitle(R.string.pref_autofill_enable_title)
|
setTitle(R.string.pref_autofill_enable_title)
|
||||||
if (enableOreoAutofill && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (enableOreoAutofill && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
@SuppressLint("InflateParams")
|
@SuppressLint("InflateParams")
|
||||||
@@ -480,10 +482,8 @@ class UserPreference : AppCompatActivity() {
|
|||||||
.setTitle(this.resources.getString(R.string.external_repository_dialog_title))
|
.setTitle(this.resources.getString(R.string.external_repository_dialog_title))
|
||||||
.setMessage(this.resources.getString(R.string.external_repository_dialog_text))
|
.setMessage(this.resources.getString(R.string.external_repository_dialog_text))
|
||||||
.setPositiveButton(R.string.dialog_ok) { _, _ ->
|
.setPositiveButton(R.string.dialog_ok) { _, _ ->
|
||||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
registerForActivityResult(OpenDocumentTree()) { uri: Uri? ->
|
||||||
registerForActivityResult(StartActivityForResult()) { result ->
|
if (uri == null) return@registerForActivityResult
|
||||||
if (!validateResult(result)) return@registerForActivityResult
|
|
||||||
val uri = result.data?.data
|
|
||||||
|
|
||||||
tag(TAG).d { "Selected repository URI is $uri" }
|
tag(TAG).d { "Selected repository URI is $uri" }
|
||||||
// TODO: This is fragile. Workaround until PasswordItem is backed by DocumentFile
|
// TODO: This is fragile. Workaround until PasswordItem is backed by DocumentFile
|
||||||
@@ -491,7 +491,7 @@ class UserPreference : AppCompatActivity() {
|
|||||||
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
val path = if (split.size > 1) split[1] else split[0]
|
val path = if (split.size > 1) split[1] else split[0]
|
||||||
val repoPath = "${Environment.getExternalStorageDirectory()}/$path"
|
val repoPath = "${Environment.getExternalStorageDirectory()}/$path"
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
val prefs = sharedPrefs
|
||||||
|
|
||||||
tag(TAG).d { "Selected repository path is $repoPath" }
|
tag(TAG).d { "Selected repository path is $repoPath" }
|
||||||
|
|
||||||
@@ -500,14 +500,14 @@ class UserPreference : AppCompatActivity() {
|
|||||||
.setTitle(getString(R.string.sdcard_root_warning_title))
|
.setTitle(getString(R.string.sdcard_root_warning_title))
|
||||||
.setMessage(getString(R.string.sdcard_root_warning_message))
|
.setMessage(getString(R.string.sdcard_root_warning_message))
|
||||||
.setPositiveButton("Remove everything") { _, _ ->
|
.setPositiveButton("Remove everything") { _, _ ->
|
||||||
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, uri?.path) }
|
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, uri.path) }
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.dialog_cancel, null)
|
.setNegativeButton(R.string.dialog_cancel, null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, repoPath) }
|
prefs.edit { putString(PreferenceKeys.GIT_EXTERNAL_REPO, repoPath) }
|
||||||
|
|
||||||
}.launch(Intent.createChooser(i, "Choose Directory"))
|
}.launch(null)
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.dialog_cancel, null)
|
.setNegativeButton(R.string.dialog_cancel, null)
|
||||||
.show()
|
.show()
|
||||||
@@ -527,29 +527,13 @@ class UserPreference : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a [ActivityResult], validates that the result is usable.
|
|
||||||
*/
|
|
||||||
private fun validateResult(result: ActivityResult): Boolean {
|
|
||||||
if (result.resultCode != RESULT_OK) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (result.data == null) {
|
|
||||||
setResult(RESULT_CANCELED)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a file explorer to import the private key
|
* Opens a file explorer to import the private key
|
||||||
*/
|
*/
|
||||||
private fun getSshKey() {
|
private fun getSshKey() {
|
||||||
registerForActivityResult(StartActivityForResult()) { result ->
|
registerForActivityResult(OpenDocument()) { uri: Uri? ->
|
||||||
if (!validateResult(result)) return@registerForActivityResult
|
if (uri == null) return@registerForActivityResult
|
||||||
try {
|
try {
|
||||||
val uri: Uri = result.data?.data ?: throw IOException("Unable to open file")
|
|
||||||
|
|
||||||
copySshKey(uri)
|
copySshKey(uri)
|
||||||
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
@@ -557,7 +541,7 @@ class UserPreference : AppCompatActivity() {
|
|||||||
this.resources.getString(R.string.ssh_key_success_dialog_title),
|
this.resources.getString(R.string.ssh_key_success_dialog_title),
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
val prefs = sharedPrefs
|
||||||
|
|
||||||
prefs.edit { putBoolean(PreferenceKeys.USE_GENERATED_KEY, false) }
|
prefs.edit { putBoolean(PreferenceKeys.USE_GENERATED_KEY, false) }
|
||||||
getEncryptedPrefs("git_operation").edit { remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE) }
|
getEncryptedPrefs("git_operation").edit { remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE) }
|
||||||
@@ -574,44 +558,39 @@ class UserPreference : AppCompatActivity() {
|
|||||||
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
|
.setPositiveButton(resources.getString(R.string.dialog_ok), null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}.launch(Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
}.launch(arrayOf("*/*"))
|
||||||
addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
type = "*/*"
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports the passwords
|
* Exports the passwords
|
||||||
*/
|
*/
|
||||||
private fun exportPasswords() {
|
private fun exportPasswords() {
|
||||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
|
registerForActivityResult(object : OpenDocumentTree() {
|
||||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
override fun createIntent(context: Context, input: Uri?): Intent {
|
||||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
|
return super.createIntent(context, input).apply {
|
||||||
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
|
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||||
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
|
||||||
}
|
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
|
||||||
|
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
|
||||||
registerForActivityResult(StartActivityForResult()) { result ->
|
|
||||||
if (!validateResult(result)) return@registerForActivityResult
|
|
||||||
val uri = result.data?.data
|
|
||||||
|
|
||||||
if (uri != null) {
|
|
||||||
val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri)
|
|
||||||
|
|
||||||
if (targetDirectory != null) {
|
|
||||||
val service = Intent(applicationContext, PasswordExportService::class.java).apply {
|
|
||||||
action = PasswordExportService.ACTION_EXPORT_PASSWORD
|
|
||||||
putExtra("uri", uri)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
startForegroundService(service)
|
|
||||||
} else {
|
|
||||||
startService(service)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.launch(intent)
|
}) { uri: Uri? ->
|
||||||
|
if (uri == null) return@registerForActivityResult
|
||||||
|
val targetDirectory = DocumentFile.fromTreeUri(applicationContext, uri)
|
||||||
|
|
||||||
|
if (targetDirectory != null) {
|
||||||
|
val service = Intent(applicationContext, PasswordExportService::class.java).apply {
|
||||||
|
action = PasswordExportService.ACTION_EXPORT_PASSWORD
|
||||||
|
putExtra("uri", uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
startForegroundService(service)
|
||||||
|
} else {
|
||||||
|
startService(service)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.launch(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -630,18 +609,16 @@ class UserPreference : AppCompatActivity() {
|
|||||||
* Pick custom xkpwd dictionary from sdcard
|
* Pick custom xkpwd dictionary from sdcard
|
||||||
*/
|
*/
|
||||||
private fun storeCustomDictionaryPath() {
|
private fun storeCustomDictionaryPath() {
|
||||||
registerForActivityResult(StartActivityForResult()) { result ->
|
registerForActivityResult(OpenDocument()) { uri ->
|
||||||
if (!validateResult(result)) return@registerForActivityResult
|
if (uri == null) return@registerForActivityResult
|
||||||
val uri: Uri = result.data?.data ?: throw IOException("Unable to open file")
|
|
||||||
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this,
|
this,
|
||||||
this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
|
this.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
|
||||||
|
|
||||||
prefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) }
|
sharedPrefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) }
|
||||||
|
|
||||||
val customDictPref = prefsFragment.findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
|
val customDictPref = prefsFragment.findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
|
||||||
setCustomDictSummary(customDictPref, uri)
|
setCustomDictSummary(customDictPref, uri)
|
||||||
@@ -653,10 +630,7 @@ class UserPreference : AppCompatActivity() {
|
|||||||
customDictFile.close()
|
customDictFile.close()
|
||||||
|
|
||||||
setResult(RESULT_OK)
|
setResult(RESULT_OK)
|
||||||
}.launch(Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
}.launch(arrayOf("*/*"))
|
||||||
addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
type = "*/*"
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IllegalArgumentException::class, IOException::class)
|
@Throws(IllegalArgumentException::class, IOException::class)
|
||||||
|
@@ -76,7 +76,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setPickedPassword(path: String) {
|
fun setPickedPassword(path: String) {
|
||||||
items.add(File("${PasswordRepository.getRepositoryDirectory(applicationContext)}/$path.gpg"))
|
items.add(File("${PasswordRepository.getRepositoryDirectory()}/$path.gpg"))
|
||||||
bindDecryptAndVerify()
|
bindDecryptAndVerify()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,9 +296,9 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||||||
when (preference) {
|
when (preference) {
|
||||||
"/first" -> {
|
"/first" -> {
|
||||||
if (!PasswordRepository.isInitialized) {
|
if (!PasswordRepository.isInitialized) {
|
||||||
PasswordRepository.initialize(this)
|
PasswordRepository.initialize()
|
||||||
}
|
}
|
||||||
items = searchPasswords(PasswordRepository.getRepositoryDirectory(this), webViewTitle)
|
items = searchPasswords(PasswordRepository.getRepositoryDirectory(), webViewTitle)
|
||||||
}
|
}
|
||||||
"/never" -> items = ArrayList()
|
"/never" -> items = ArrayList()
|
||||||
else -> getPreferredPasswords(preference)
|
else -> getPreferredPasswords(preference)
|
||||||
@@ -318,9 +318,9 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||||||
when (preference) {
|
when (preference) {
|
||||||
"/first" -> {
|
"/first" -> {
|
||||||
if (!PasswordRepository.isInitialized) {
|
if (!PasswordRepository.isInitialized) {
|
||||||
PasswordRepository.initialize(this)
|
PasswordRepository.initialize()
|
||||||
}
|
}
|
||||||
items = searchPasswords(PasswordRepository.getRepositoryDirectory(this), appName)
|
items = searchPasswords(PasswordRepository.getRepositoryDirectory(), appName)
|
||||||
}
|
}
|
||||||
"/never" -> items = ArrayList()
|
"/never" -> items = ArrayList()
|
||||||
else -> getPreferredPasswords(preference)
|
else -> getPreferredPasswords(preference)
|
||||||
@@ -331,12 +331,12 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||||||
// file into the items list.
|
// file into the items list.
|
||||||
private fun getPreferredPasswords(preference: String) {
|
private fun getPreferredPasswords(preference: String) {
|
||||||
if (!PasswordRepository.isInitialized) {
|
if (!PasswordRepository.isInitialized) {
|
||||||
PasswordRepository.initialize(this)
|
PasswordRepository.initialize()
|
||||||
}
|
}
|
||||||
val preferredPasswords = preference.splitLines()
|
val preferredPasswords = preference.splitLines()
|
||||||
items = ArrayList()
|
items = ArrayList()
|
||||||
for (password in preferredPasswords) {
|
for (password in preferredPasswords) {
|
||||||
val path = PasswordRepository.getRepositoryDirectory(applicationContext).toString() + "/" + password + ".gpg"
|
val path = PasswordRepository.getRepositoryDirectory().toString() + "/" + password + ".gpg"
|
||||||
if (File(path).exists()) {
|
if (File(path).exists()) {
|
||||||
items.add(File(path))
|
items.add(File(path))
|
||||||
}
|
}
|
||||||
@@ -417,7 +417,7 @@ class AutofillService : AccessibilityService(), CoroutineScope by CoroutineScope
|
|||||||
// populate the dialog items, always with pick + pick and match. Could
|
// populate the dialog items, always with pick + pick and match. Could
|
||||||
// make it optional (or make height a setting for the same effect)
|
// make it optional (or make height a setting for the same effect)
|
||||||
val itemNames = arrayOfNulls<CharSequence>(items.size + 2)
|
val itemNames = arrayOfNulls<CharSequence>(items.size + 2)
|
||||||
val passwordDirectory = PasswordRepository.getRepositoryDirectory(applicationContext).toString()
|
val passwordDirectory = PasswordRepository.getRepositoryDirectory().toString()
|
||||||
val autofillFullPath = settings!!.getBoolean(PreferenceKeys.AUTOFILL_FULL_PATH, false)
|
val autofillFullPath = settings!!.getBoolean(PreferenceKeys.AUTOFILL_FULL_PATH, false)
|
||||||
for (i in items.indices) {
|
for (i in items.indices) {
|
||||||
if (autofillFullPath) {
|
if (autofillFullPath) {
|
||||||
|
@@ -121,7 +121,7 @@ private fun makeRemoteView(
|
|||||||
fun makeFillMatchRemoteView(context: Context, file: File, formOrigin: FormOrigin): RemoteViews {
|
fun makeFillMatchRemoteView(context: Context, file: File, formOrigin: FormOrigin): RemoteViews {
|
||||||
val title = formOrigin.getPrettyIdentifier(context, untrusted = false)
|
val title = formOrigin.getPrettyIdentifier(context, untrusted = false)
|
||||||
val directoryStructure = AutofillPreferences.directoryStructure(context)
|
val directoryStructure = AutofillPreferences.directoryStructure(context)
|
||||||
val relativeFile = file.relativeTo(PasswordRepository.getRepositoryDirectory(context))
|
val relativeFile = file.relativeTo(PasswordRepository.getRepositoryDirectory())
|
||||||
val summary = directoryStructure.getUsernameFor(relativeFile)
|
val summary = directoryStructure.getUsernameFor(relativeFile)
|
||||||
?: directoryStructure.getPathToIdentifierFor(relativeFile) ?: ""
|
?: directoryStructure.getPathToIdentifierFor(relativeFile) ?: ""
|
||||||
val iconRes = R.drawable.ic_person_black_24dp
|
val iconRes = R.drawable.ic_person_black_24dp
|
||||||
|
@@ -9,12 +9,10 @@ import android.content.SharedPreferences
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
|
|
||||||
private val Context.defaultSharedPreferences: SharedPreferences
|
|
||||||
get() = PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
|
|
||||||
enum class DirectoryStructure(val value: String) {
|
enum class DirectoryStructure(val value: String) {
|
||||||
EncryptedUsername("encrypted_username"),
|
EncryptedUsername("encrypted_username"),
|
||||||
FileBased("file"),
|
FileBased("file"),
|
||||||
@@ -122,8 +120,7 @@ enum class DirectoryStructure(val value: String) {
|
|||||||
object AutofillPreferences {
|
object AutofillPreferences {
|
||||||
|
|
||||||
fun directoryStructure(context: Context): DirectoryStructure {
|
fun directoryStructure(context: Context): DirectoryStructure {
|
||||||
val value =
|
val value = context.sharedPrefs.getString(DirectoryStructure.PREFERENCE, null)
|
||||||
context.defaultSharedPreferences.getString(DirectoryStructure.PREFERENCE, null)
|
|
||||||
return DirectoryStructure.fromValue(value)
|
return DirectoryStructure.fromValue(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@ import android.content.Context
|
|||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
|
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
|
||||||
|
|
||||||
@@ -68,8 +69,7 @@ fun getSuffixPlusUpToOne(domain: String, suffix: String): String? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getCustomSuffixes(context: Context): Sequence<String> {
|
fun getCustomSuffixes(context: Context): Sequence<String> {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
return context.sharedPrefs.getString(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES, "")!!
|
||||||
return prefs.getString(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES, "")!!
|
|
||||||
.splitToSequence('\n')
|
.splitToSequence('\n')
|
||||||
.filter { it.isNotBlank() && it.first() != '.' && it.last() != '.' }
|
.filter { it.isNotBlank() && it.first() != '.' && it.last() != '.' }
|
||||||
}
|
}
|
||||||
|
@@ -100,7 +100,7 @@ class AutofillSaveActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val repo = PasswordRepository.getRepositoryDirectory(applicationContext)
|
val repo = PasswordRepository.getRepositoryDirectory()
|
||||||
val saveIntent = Intent(this, PasswordCreationActivity::class.java).apply {
|
val saveIntent = Intent(this, PasswordCreationActivity::class.java).apply {
|
||||||
putExtras(
|
putExtras(
|
||||||
bundleOf(
|
bundleOf(
|
||||||
|
@@ -27,6 +27,7 @@ import com.zeapo.pwdstore.R
|
|||||||
import com.zeapo.pwdstore.utils.OPENPGP_PROVIDER
|
import com.zeapo.pwdstore.utils.OPENPGP_PROVIDER
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
import com.zeapo.pwdstore.utils.clipboard
|
import com.zeapo.pwdstore.utils.clipboard
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import com.zeapo.pwdstore.utils.snackbar
|
import com.zeapo.pwdstore.utils.snackbar
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import me.msfjarvis.openpgpktx.util.OpenPgpApi
|
import me.msfjarvis.openpgpktx.util.OpenPgpApi
|
||||||
@@ -69,7 +70,7 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
|
|||||||
/**
|
/**
|
||||||
* [SharedPreferences] instance used by subclasses to persist settings
|
* [SharedPreferences] instance used by subclasses to persist settings
|
||||||
*/
|
*/
|
||||||
val settings: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
|
val settings: SharedPreferences by lazy { sharedPrefs }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle to the [OpenPgpApi] instance that is used by subclasses to interface with OpenKeychain.
|
* Handle to the [OpenPgpApi] instance that is used by subclasses to interface with OpenKeychain.
|
||||||
|
@@ -304,7 +304,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
|
|||||||
data.action = OpenPgpApi.ACTION_ENCRYPT
|
data.action = OpenPgpApi.ACTION_ENCRYPT
|
||||||
|
|
||||||
// pass enters the key ID into `.gpg-id`.
|
// pass enters the key ID into `.gpg-id`.
|
||||||
val repoRoot = PasswordRepository.getRepositoryDirectory(applicationContext)
|
val repoRoot = PasswordRepository.getRepositoryDirectory()
|
||||||
val gpgIdentifierFile = File(repoRoot, directory.text.toString()).findTillRoot(".gpg-id", repoRoot)
|
val gpgIdentifierFile = File(repoRoot, directory.text.toString()).findTillRoot(".gpg-id", repoRoot)
|
||||||
if (gpgIdentifierFile == null) {
|
if (gpgIdentifierFile == null) {
|
||||||
snackbar(message = resources.getString(R.string.failed_to_find_key_id))
|
snackbar(message = resources.getString(R.string.failed_to_find_key_id))
|
||||||
@@ -391,7 +391,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
|
|||||||
return@executeApiAsync
|
return@executeApiAsync
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isInsideRepository(file)) {
|
if (!file.isInsideRepository()) {
|
||||||
snackbar(message = getString(R.string.message_error_destination_outside_repo))
|
snackbar(message = getString(R.string.message_error_destination_outside_repo))
|
||||||
return@executeApiAsync
|
return@executeApiAsync
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,6 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.core.text.isDigitsOnly
|
import androidx.core.text.isDigitsOnly
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import com.github.ajalt.timberkt.Timber.tag
|
import com.github.ajalt.timberkt.Timber.tag
|
||||||
import com.github.ajalt.timberkt.e
|
import com.github.ajalt.timberkt.e
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
@@ -31,6 +30,7 @@ import com.zeapo.pwdstore.git.operation.SyncOperation
|
|||||||
import com.zeapo.pwdstore.utils.PasswordRepository
|
import com.zeapo.pwdstore.utils.PasswordRepository
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -61,7 +61,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
settings = PreferenceManager.getDefaultSharedPreferences(this)
|
settings = sharedPrefs
|
||||||
encryptedSettings = getEncryptedPrefs("git_operation")
|
encryptedSettings = getEncryptedPrefs("git_operation")
|
||||||
protocol = Protocol.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_PROTOCOL, null))
|
protocol = Protocol.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_PROTOCOL, null))
|
||||||
connectionMode = ConnectionMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH, null))
|
connectionMode = ConnectionMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH, null))
|
||||||
@@ -197,7 +197,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory(this))
|
val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory())
|
||||||
val op = when (operation) {
|
val op = when (operation) {
|
||||||
REQUEST_CLONE, GitOperation.GET_SSH_KEY_FROM_CLONE -> CloneOperation(localDir, url!!, this)
|
REQUEST_CLONE, GitOperation.GET_SSH_KEY_FROM_CLONE -> CloneOperation(localDir, url!!, this)
|
||||||
REQUEST_PULL -> PullOperation(localDir, this)
|
REQUEST_PULL -> PullOperation(localDir, this)
|
||||||
|
@@ -34,7 +34,7 @@ class GitConfigActivity : BaseGitActivity() {
|
|||||||
else
|
else
|
||||||
binding.gitUserName.setText(username)
|
binding.gitUserName.setText(username)
|
||||||
binding.gitUserEmail.setText(email)
|
binding.gitUserEmail.setText(email)
|
||||||
val repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory(this))
|
val repo = PasswordRepository.getRepository(PasswordRepository.getRepositoryDirectory())
|
||||||
if (repo != null) {
|
if (repo != null) {
|
||||||
try {
|
try {
|
||||||
val objectId = repo.resolve(Constants.HEAD)
|
val objectId = repo.resolve(Constants.HEAD)
|
||||||
|
@@ -113,7 +113,7 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||||||
|
|
||||||
binding.saveButton.setOnClickListener {
|
binding.saveButton.setOnClickListener {
|
||||||
if (isClone && PasswordRepository.getRepository(null) == null)
|
if (isClone && PasswordRepository.getRepository(null) == null)
|
||||||
PasswordRepository.initialize(this)
|
PasswordRepository.initialize()
|
||||||
when (val result = updateUrl()) {
|
when (val result = updateUrl()) {
|
||||||
GitUpdateUrlResult.Ok -> {
|
GitUpdateUrlResult.Ok -> {
|
||||||
settings.edit {
|
settings.edit {
|
||||||
@@ -161,7 +161,7 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||||||
* Clones the repository, the directory exists, deletes it
|
* Clones the repository, the directory exists, deletes it
|
||||||
*/
|
*/
|
||||||
private fun cloneRepository() {
|
private fun cloneRepository() {
|
||||||
val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory(this))
|
val localDir = requireNotNull(PasswordRepository.getRepositoryDirectory())
|
||||||
val localDirFiles = localDir.listFiles() ?: emptyArray()
|
val localDirFiles = localDir.listFiles() ?: emptyArray()
|
||||||
// Warn if non-empty folder unless it's a just-initialized store that has just a .git folder
|
// Warn if non-empty folder unless it's a just-initialized store that has just a .git folder
|
||||||
if (localDir.exists() && localDirFiles.isNotEmpty() &&
|
if (localDir.exists() && localDirFiles.isNotEmpty() &&
|
||||||
|
@@ -158,9 +158,7 @@ abstract class GitOperation(gitDir: File, internal val callingActivity: Fragment
|
|||||||
.edit { remove(PreferenceKeys.SSH_OPENKEYSTORE_KEYID) }
|
.edit { remove(PreferenceKeys.SSH_OPENKEYSTORE_KEYID) }
|
||||||
}
|
}
|
||||||
is SshjSessionFactory -> {
|
is SshjSessionFactory -> {
|
||||||
callingActivity.applicationContext
|
callingActivity.getEncryptedPrefs("git_operation").edit {
|
||||||
.getEncryptedPrefs("git_operation")
|
|
||||||
.edit {
|
|
||||||
remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE)
|
remove(PreferenceKeys.SSH_KEY_LOCAL_PASSPHRASE)
|
||||||
remove(PreferenceKeys.HTTPS_PASSWORD)
|
remove(PreferenceKeys.HTTPS_PASSWORD)
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@ import android.content.Context
|
|||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class XkpwdDictionary(context: Context) {
|
class XkpwdDictionary(context: Context) {
|
||||||
@@ -15,7 +16,7 @@ class XkpwdDictionary(context: Context) {
|
|||||||
val words: Map<Int, List<String>>
|
val words: Map<Int, List<String>>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
val prefs = context.sharedPrefs
|
||||||
val uri = prefs.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, "")!!
|
val uri = prefs.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, "")!!
|
||||||
val customDictFile = File(context.filesDir, XKPWD_CUSTOM_DICT_FILE)
|
val customDictFile = File(context.filesDir, XKPWD_CUSTOM_DICT_FILE)
|
||||||
|
|
||||||
|
@@ -19,6 +19,7 @@ import com.jcraft.jsch.KeyPair
|
|||||||
import com.zeapo.pwdstore.R
|
import com.zeapo.pwdstore.R
|
||||||
import com.zeapo.pwdstore.databinding.ActivitySshKeygenBinding
|
import com.zeapo.pwdstore.databinding.ActivitySshKeygenBinding
|
||||||
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
import com.zeapo.pwdstore.utils.getEncryptedPrefs
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import com.zeapo.pwdstore.utils.viewBinding
|
import com.zeapo.pwdstore.utils.viewBinding
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
@@ -91,8 +92,7 @@ class SshKeyGenActivity : AppCompatActivity() {
|
|||||||
if (e == null) {
|
if (e == null) {
|
||||||
val df = ShowSshKeyFragment()
|
val df = ShowSshKeyFragment()
|
||||||
df.show(supportFragmentManager, "public_key")
|
df.show(supportFragmentManager, "public_key")
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
sharedPrefs.edit { putBoolean("use_generated_key", true) }
|
||||||
prefs.edit { putBoolean("use_generated_key", true) }
|
|
||||||
} else {
|
} else {
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(getString(R.string.error_generate_ssh_key))
|
.setTitle(getString(R.string.error_generate_ssh_key))
|
||||||
|
@@ -19,6 +19,7 @@ import com.zeapo.pwdstore.SearchableRepositoryAdapter
|
|||||||
import com.zeapo.pwdstore.stableId
|
import com.zeapo.pwdstore.stableId
|
||||||
import com.zeapo.pwdstore.utils.PasswordItem
|
import com.zeapo.pwdstore.utils.PasswordItem
|
||||||
import com.zeapo.pwdstore.utils.PreferenceKeys
|
import com.zeapo.pwdstore.utils.PreferenceKeys
|
||||||
|
import com.zeapo.pwdstore.utils.sharedPrefs
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
open class PasswordItemRecyclerAdapter :
|
open class PasswordItemRecyclerAdapter :
|
||||||
@@ -49,8 +50,7 @@ open class PasswordItemRecyclerAdapter :
|
|||||||
lateinit var itemDetails: ItemDetailsLookup.ItemDetails<String>
|
lateinit var itemDetails: ItemDetailsLookup.ItemDetails<String>
|
||||||
|
|
||||||
fun bind(item: PasswordItem) {
|
fun bind(item: PasswordItem) {
|
||||||
val settings =
|
val settings = itemView.context.sharedPrefs
|
||||||
PreferenceManager.getDefaultSharedPreferences(itemView.context.applicationContext)
|
|
||||||
val showHidden = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
|
val showHidden = settings.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)
|
||||||
val parentPath = item.fullPathToParent.replace("(^/)|(/$)".toRegex(), "")
|
val parentPath = item.fullPathToParent.replace("(^/)|(/$)".toRegex(), "")
|
||||||
val source = if (parentPath.isNotEmpty()) {
|
val source = if (parentPath.isNotEmpty()) {
|
||||||
|
@@ -18,6 +18,7 @@ import androidx.annotation.RequiresApi
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.security.crypto.EncryptedSharedPreferences
|
import androidx.security.crypto.EncryptedSharedPreferences
|
||||||
import androidx.security.crypto.MasterKey
|
import androidx.security.crypto.MasterKey
|
||||||
import com.github.ajalt.timberkt.d
|
import com.github.ajalt.timberkt.d
|
||||||
@@ -97,6 +98,9 @@ fun Context.getEncryptedPrefs(fileName: String): SharedPreferences {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val Context.sharedPrefs: SharedPreferences
|
||||||
|
get() = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||||
|
|
||||||
suspend fun FragmentActivity.commitChange(
|
suspend fun FragmentActivity.commitChange(
|
||||||
message: String,
|
message: String,
|
||||||
finishWithResultOnEnd: Intent? = null,
|
finishWithResultOnEnd: Intent? = null,
|
||||||
@@ -109,7 +113,7 @@ suspend fun FragmentActivity.commitChange(
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
object : GitOperation(getRepositoryDirectory(this@commitChange), this@commitChange) {
|
object : GitOperation(getRepositoryDirectory(), this@commitChange) {
|
||||||
override val commands = arrayOf(
|
override val commands = arrayOf(
|
||||||
git.add().addFilepattern("."),
|
git.add().addFilepattern("."),
|
||||||
git.status(),
|
git.status(),
|
||||||
@@ -151,6 +155,6 @@ val Context.autofillManager: AutofillManager?
|
|||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
get() = getSystemService()
|
get() = getSystemService()
|
||||||
|
|
||||||
fun FragmentActivity.isInsideRepository(file: File): Boolean {
|
fun File.isInsideRepository(): Boolean {
|
||||||
return file.canonicalPath.contains(getRepositoryDirectory(this).canonicalPath)
|
return canonicalPath.contains(getRepositoryDirectory().canonicalPath)
|
||||||
}
|
}
|
||||||
|
@@ -4,10 +4,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.zeapo.pwdstore.utils
|
package com.zeapo.pwdstore.utils
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.preference.PreferenceManager
|
import com.zeapo.pwdstore.Application
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileFilter
|
import java.io.FileFilter
|
||||||
import java.util.Comparator
|
import java.util.Comparator
|
||||||
@@ -49,7 +48,9 @@ open class PasswordRepository protected constructor() {
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private var repository: Repository? = null
|
private var repository: Repository? = null
|
||||||
private lateinit var settings: SharedPreferences
|
private val settings by lazy { Application.instance.sharedPrefs }
|
||||||
|
private val filesDir
|
||||||
|
get() = Application.instance.filesDir
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the git repository
|
* Returns the git repository
|
||||||
@@ -152,27 +153,21 @@ open class PasswordRepository protected constructor() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getRepositoryDirectory(context: Context): File {
|
fun getRepositoryDirectory(): File {
|
||||||
if (!::settings.isInitialized) {
|
|
||||||
settings = PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
|
|
||||||
}
|
|
||||||
return if (settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)) {
|
return if (settings.getBoolean(PreferenceKeys.GIT_EXTERNAL, false)) {
|
||||||
val externalRepo = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO, null)
|
val externalRepo = settings.getString(PreferenceKeys.GIT_EXTERNAL_REPO, null)
|
||||||
if (externalRepo != null)
|
if (externalRepo != null)
|
||||||
File(externalRepo)
|
File(externalRepo)
|
||||||
else
|
else
|
||||||
File(context.filesDir.toString(), "/store")
|
File(filesDir.toString(), "/store")
|
||||||
} else {
|
} else {
|
||||||
File(context.filesDir.toString(), "/store")
|
File(filesDir.toString(), "/store")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun initialize(context: Context): Repository? {
|
fun initialize(): Repository? {
|
||||||
if (!::settings.isInitialized) {
|
val dir = getRepositoryDirectory()
|
||||||
settings = PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
|
|
||||||
}
|
|
||||||
val dir = getRepositoryDirectory(context)
|
|
||||||
// uninitialize the repo if the dir does not exist or is absolutely empty
|
// uninitialize the repo if the dir does not exist or is absolutely empty
|
||||||
settings.edit {
|
settings.edit {
|
||||||
if (!dir.exists() || !dir.isDirectory || dir.listFiles()!!.isEmpty()) {
|
if (!dir.exists() || !dir.isDirectory || dir.listFiles()!!.isEmpty()) {
|
||||||
|
Reference in New Issue
Block a user