diff --git a/CHANGELOG.md b/CHANGELOG.md
index 35f99d5c1..23b188a31 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,6 +28,7 @@ All notable changes to this project will be documented in this file.
- OTP codes can be automatically filled from SMS (requires Android P+ and Google Play Services)
- Importing TOTP secrets using QR codes
- Navigate into newly created folders and scroll to newly created passwords
+- Support per-directory keys
## [1.9.2] - 2020-06-30
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5fcbe7069..1fea64bad 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -83,11 +83,6 @@
android:parentActivityName=".PasswordStore"
android:windowSoftInputMode="adjustResize" />
-
-
- val intent = Intent(activity, UserPreference::class.java)
- repositoryInitAction.launch(intent)
- }
- .setNegativeButton(resources.getString(R.string.dialog_negative), null)
- .show()
- }
createRepository()
}
@@ -580,17 +569,6 @@ class PasswordStore : AppCompatActivity(R.layout.activity_pwdstore) {
.show()
return false
}
- if (settings.getStringSet(PreferenceKeys.OPENPGP_KEY_IDS_SET, HashSet()).isNullOrEmpty()) {
- MaterialAlertDialogBuilder(this)
- .setTitle(resources.getString(R.string.no_key_selected_dialog_title))
- .setMessage(resources.getString(R.string.no_key_selected_dialog_text))
- .setPositiveButton(resources.getString(R.string.dialog_ok)) { _, _ ->
- val intent = Intent(activity, UserPreference::class.java)
- startActivity(intent)
- }
- .show()
- return false
- }
return true
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
index f713ad26a..98873fada 100644
--- a/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/UserPreference.kt
@@ -39,12 +39,10 @@ import com.github.ajalt.timberkt.Timber.tag
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.w
import com.google.android.material.dialog.MaterialAlertDialogBuilder
-import com.google.android.material.snackbar.Snackbar
import com.zeapo.pwdstore.autofill.AutofillPreferenceActivity
import com.zeapo.pwdstore.autofill.oreo.BrowserAutofillSupportLevel
import com.zeapo.pwdstore.autofill.oreo.getInstalledBrowsersWithAutofillSupportLevel
import com.zeapo.pwdstore.crypto.BasePgpActivity
-import com.zeapo.pwdstore.crypto.GetKeyIdsActivity
import com.zeapo.pwdstore.git.GitConfigActivity
import com.zeapo.pwdstore.git.GitServerConfigActivity
import com.zeapo.pwdstore.pwgenxkpwd.XkpwdDictionary
@@ -57,8 +55,6 @@ import com.zeapo.pwdstore.utils.autofillManager
import com.zeapo.pwdstore.utils.getEncryptedPrefs
import java.io.File
import java.io.IOException
-import java.util.HashSet
-import me.msfjarvis.openpgpktx.util.OpenPgpUtils
typealias ClickListener = Preference.OnPreferenceClickListener
typealias ChangeListener = Preference.OnPreferenceChangeListener
@@ -106,9 +102,6 @@ class UserPreference : AppCompatActivity() {
}
}
- // Crypto preferences
- val keyPreference = findPreference(PreferenceKeys.OPENPGP_KEY_ID_PREF)
-
// General preferences
val showTimePreference = findPreference(PreferenceKeys.GENERAL_SHOW_TIME)
val clearClipboard20xPreference = findPreference(PreferenceKeys.CLEAR_CLIPBOARD_20X)
@@ -155,24 +148,6 @@ class UserPreference : AppCompatActivity() {
appVersionPreference?.summary = "Version: ${BuildConfig.VERSION_NAME}"
- keyPreference?.let { pref ->
- updateKeyIDsSummary(pref)
- pref.onPreferenceClickListener = ClickListener {
- val providerPackageName = requireNotNull(sharedPreferences.getString(PreferenceKeys.OPENPGP_PROVIDER_LIST, ""))
- if (providerPackageName.isEmpty()) {
- Snackbar.make(requireView(), resources.getString(R.string.provider_toast_text), Snackbar.LENGTH_LONG).show()
- false
- } else {
- val intent = Intent(callingActivity, GetKeyIdsActivity::class.java)
- val keySelectResult = registerForActivityResult(StartActivityForResult()) {
- updateKeyIDsSummary(pref)
- }
- keySelectResult.launch(intent)
- true
- }
- }
- }
-
sshKeyPreference?.onPreferenceClickListener = ClickListener {
callingActivity.getSshKey()
true
@@ -369,18 +344,6 @@ class UserPreference : AppCompatActivity() {
}
}
- private fun updateKeyIDsSummary(preference: Preference) {
- val selectedKeys = (sharedPreferences.getStringSet(PreferenceKeys.OPENPGP_KEY_IDS_SET, null)
- ?: HashSet()).toTypedArray()
- preference.summary = if (selectedKeys.isEmpty()) {
- resources.getString(R.string.pref_no_key_selected)
- } else {
- selectedKeys.joinToString(separator = ";") { s ->
- OpenPgpUtils.convertKeyIdToHex(s.toLong())
- }
- }
- }
-
private fun updateXkPasswdPrefsVisibility(newValue: Any?, prefIsCustomDict: CheckBoxPreference?, prefCustomDictPicker: Preference?) {
when (newValue as String) {
BasePgpActivity.KEY_PWGEN_TYPE_CLASSIC -> {
diff --git a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillDecryptActivity.kt b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillDecryptActivity.kt
index eabd24c0a..3656bc7e1 100644
--- a/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillDecryptActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/autofill/oreo/ui/AutofillDecryptActivity.kt
@@ -24,6 +24,7 @@ import com.zeapo.pwdstore.autofill.oreo.Credentials
import com.zeapo.pwdstore.autofill.oreo.DirectoryStructure
import com.zeapo.pwdstore.autofill.oreo.FillableForm
import com.zeapo.pwdstore.model.PasswordEntry
+import com.zeapo.pwdstore.utils.OPENPGP_PROVIDER
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileNotFoundException
@@ -53,7 +54,6 @@ class AutofillDecryptActivity : AppCompatActivity(), CoroutineScope {
private const val EXTRA_FILE_PATH = "com.zeapo.pwdstore.autofill.oreo.EXTRA_FILE_PATH"
private const val EXTRA_SEARCH_ACTION =
"com.zeapo.pwdstore.autofill.oreo.EXTRA_SEARCH_ACTION"
- private const val OPENPGP_PROVIDER = "org.sufficientlysecure.keychain"
private var decryptFileRequestCode = 1
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt
index 39164e8f1..ec8e7f9bb 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/BasePgpActivity.kt
@@ -14,8 +14,6 @@ import android.os.Build
import android.os.Bundle
import android.text.format.DateUtils
import android.view.WindowManager
-import android.widget.Toast
-import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.CallSuper
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
@@ -26,7 +24,7 @@ import com.github.ajalt.timberkt.i
import com.google.android.material.snackbar.Snackbar
import com.zeapo.pwdstore.ClipboardService
import com.zeapo.pwdstore.R
-import com.zeapo.pwdstore.UserPreference
+import com.zeapo.pwdstore.utils.OPENPGP_PROVIDER
import com.zeapo.pwdstore.utils.PreferenceKeys
import com.zeapo.pwdstore.utils.clipboard
import com.zeapo.pwdstore.utils.snackbar
@@ -73,12 +71,6 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
*/
val settings: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
- /**
- * Read-only field for getting the list of OpenPGP key IDs that we have access to.
- */
- var keyIDs = emptySet()
- private set
-
/**
* Handle to the [OpenPgpApi] instance that is used by subclasses to interface with OpenKeychain.
*/
@@ -87,15 +79,13 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
/**
* [onCreate] sets the window up with the right flags to prevent auth leaks through screenshots
- * or recent apps screen and fills in [keyIDs] from [settings]
+ * or recent apps screen.
*/
@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
tag(TAG)
-
- keyIDs = settings.getStringSet(PreferenceKeys.OPENPGP_KEY_IDS_SET, null) ?: emptySet()
}
/**
@@ -128,20 +118,11 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
}
/**
- * Method for subclasses to initiate binding with [OpenPgpServiceConnection]. The design choices
- * here are a bit dubious at first glance. We require passing a [ActivityResultLauncher] because
- * it lets us react to having a OpenPgp provider selected without relying on the now deprecated
- * [startActivityForResult].
+ * Method for subclasses to initiate binding with [OpenPgpServiceConnection].
*/
- fun bindToOpenKeychain(onBoundListener: OpenPgpServiceConnection.OnBound, activityResult: ActivityResultLauncher) {
- val providerPackageName = settings.getString(PreferenceKeys.OPENPGP_PROVIDER_LIST, "")
- if (providerPackageName.isNullOrEmpty()) {
- Toast.makeText(this, resources.getString(R.string.provider_toast_text), Toast.LENGTH_LONG).show()
- activityResult.launch(Intent(this, UserPreference::class.java))
- } else {
- serviceConnection = OpenPgpServiceConnection(this, providerPackageName, onBoundListener)
- serviceConnection?.bindToService()
- }
+ fun bindToOpenKeychain(onBoundListener: OpenPgpServiceConnection.OnBound) {
+ serviceConnection = OpenPgpServiceConnection(this, OPENPGP_PROVIDER, onBoundListener)
+ serviceConnection?.bindToService()
}
/**
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
index 3425a3460..cc70dcc1a 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
@@ -13,7 +13,6 @@ import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.activity.result.IntentSenderRequest
-import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.e
@@ -57,13 +56,9 @@ class DecryptActivity : BasePgpActivity(), OpenPgpServiceConnection.OnBound {
}
}
- private val openKeychainResult = registerForActivityResult(StartActivityForResult()) {
- decryptAndVerify()
- }
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- bindToOpenKeychain(this, openKeychainResult)
+ bindToOpenKeychain(this)
title = name
with(binding) {
setContentView(root)
@@ -134,7 +129,7 @@ class DecryptActivity : BasePgpActivity(), OpenPgpServiceConnection.OnBound {
@OptIn(ExperimentalTime::class)
private fun decryptAndVerify(receivedIntent: Intent? = null) {
if (api == null) {
- bindToOpenKeychain(this, openKeychainResult)
+ bindToOpenKeychain(this)
return
}
val data = receivedIntent ?: Intent()
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/GetKeyIdsActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/GetKeyIdsActivity.kt
deleted file mode 100644
index 97f6bab26..000000000
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/GetKeyIdsActivity.kt
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright © 2014-2020 The Android Password Store Authors. All Rights Reserved.
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-package com.zeapo.pwdstore.crypto
-
-import android.content.Intent
-import android.os.Bundle
-import androidx.activity.result.IntentSenderRequest
-import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
-import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult
-import androidx.core.content.edit
-import androidx.lifecycle.lifecycleScope
-import com.github.ajalt.timberkt.Timber
-import com.github.ajalt.timberkt.e
-import com.zeapo.pwdstore.utils.PreferenceKeys
-import com.zeapo.pwdstore.utils.snackbar
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import me.msfjarvis.openpgpktx.util.OpenPgpApi
-import org.openintents.openpgp.IOpenPgpService2
-
-class GetKeyIdsActivity : BasePgpActivity() {
-
- private val getKeyIds = registerForActivityResult(StartActivityForResult()) { getKeyIds() }
-
- private val userInteractionRequiredResult = registerForActivityResult(StartIntentSenderForResult()) { result ->
- if (result.data == null) {
- setResult(RESULT_CANCELED, null)
- finish()
- return@registerForActivityResult
- }
-
- when (result.resultCode) {
- RESULT_OK -> getKeyIds(result.data)
- RESULT_CANCELED -> {
- setResult(RESULT_CANCELED, result.data)
- finish()
- }
- }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- bindToOpenKeychain(this, getKeyIds)
- }
-
- override fun onBound(service: IOpenPgpService2) {
- super.onBound(service)
- getKeyIds()
- }
-
- override fun onError(e: Exception) {
- e(e)
- }
-
- /**
- * Get the Key ids from OpenKeychain
- */
- private fun getKeyIds(receivedIntent: Intent? = null) {
- val data = receivedIntent ?: Intent()
- data.action = OpenPgpApi.ACTION_GET_KEY_IDS
- lifecycleScope.launch(Dispatchers.IO) {
- api?.executeApiAsync(data, null, null) { result ->
- when (result?.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
- OpenPgpApi.RESULT_CODE_SUCCESS -> {
- try {
- val ids = result.getLongArrayExtra(OpenPgpApi.RESULT_KEY_IDS)
- ?: LongArray(0)
- val keys = ids.map { it.toString() }.toSet()
- // use Long
- settings.edit { putStringSet(PreferenceKeys.OPENPGP_KEY_IDS_SET, keys) }
- snackbar(message = "PGP keys selected")
- setResult(RESULT_OK)
- finish()
- } catch (e: Exception) {
- Timber.e(e) { "An Exception occurred" }
- }
- }
- OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED -> {
- val sender = getUserInteractionRequestIntent(result)
- userInteractionRequiredResult.launch(IntentSenderRequest.Builder(sender).build())
- }
- OpenPgpApi.RESULT_CODE_ERROR -> handleError(result)
- }
- }
- }
- }
-}
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
index 286f29517..6cacf4b90 100644
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/crypto/PasswordCreationActivity.kt
@@ -11,7 +11,10 @@ import android.text.InputType
import android.view.Menu
import android.view.MenuItem
import android.view.View
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
+import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult
import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.lifecycleScope
@@ -40,6 +43,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import me.msfjarvis.openpgpktx.util.OpenPgpApi
import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
+import me.msfjarvis.openpgpktx.util.OpenPgpUtils
import org.eclipse.jgit.api.Git
class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnBound {
@@ -51,13 +55,45 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
private val suggestedExtra by lazy { intent.getStringExtra(EXTRA_EXTRA_CONTENT) }
private val shouldGeneratePassword by lazy { intent.getBooleanExtra(EXTRA_GENERATE_PASSWORD, false) }
private val editing by lazy { intent.getBooleanExtra(EXTRA_EDITING, false) }
- private val doNothing = registerForActivityResult(StartActivityForResult()) {}
- private var oldCategory: String? = null
private val oldFileName by lazy { intent.getStringExtra(EXTRA_FILE_NAME) }
+ private var oldCategory: String? = null
+ private var copy: Boolean = false
+
+ private val userInteractionRequiredResult: ActivityResultLauncher = registerForActivityResult(StartIntentSenderForResult()) { result ->
+ if (result.data == null) {
+ setResult(RESULT_CANCELED, null)
+ finish()
+ return@registerForActivityResult
+ }
+
+ when (result.resultCode) {
+ RESULT_OK -> encrypt(result.data)
+ RESULT_CANCELED -> {
+ setResult(RESULT_CANCELED, result.data)
+ finish()
+ }
+ }
+ }
+
+ private fun File.findTillRoot(fileName: String, rootPath: File): File? {
+ val gpgFile = File(this, fileName)
+ if (gpgFile.exists()) return gpgFile
+
+ if (this.absolutePath == rootPath.absolutePath) {
+ return null
+ }
+
+ val parent = parentFile
+ return if (parent != null && parent.exists()) {
+ parent.findTillRoot(fileName, rootPath)
+ } else {
+ null
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- bindToOpenKeychain(this, doNothing)
+ bindToOpenKeychain(this)
title = if (editing)
getString(R.string.edit_password)
else
@@ -172,8 +208,14 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
setResult(RESULT_CANCELED)
finish()
}
- R.id.save_password -> encrypt()
- R.id.save_and_copy_password -> encrypt(copy = true)
+ R.id.save_password -> {
+ copy = false
+ encrypt()
+ }
+ R.id.save_and_copy_password -> {
+ copy = true
+ encrypt()
+ }
else -> return super.onOptionsItemSelected(item)
}
return true
@@ -202,10 +244,42 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
otpImportButton.isVisible = !entry.hasTotp()
}
+ private sealed class GpgIdentifier {
+ data class KeyId(val id: Long) : GpgIdentifier()
+ data class UserId(val email: String) : GpgIdentifier()
+ }
+
+ @OptIn(ExperimentalUnsignedTypes::class)
+ private fun parseGpgIdentifier(identifier: String) : GpgIdentifier? {
+ // Match long key IDs:
+ // FF22334455667788 or 0xFF22334455667788
+ val maybeLongKeyId = identifier.removePrefix("0x").takeIf {
+ it.matches("[a-fA-F0-9]{16}".toRegex())
+ }
+ if (maybeLongKeyId != null) {
+ val keyId = maybeLongKeyId.toULong()
+ return GpgIdentifier.KeyId(maybeLongKeyId.toLong())
+ }
+
+ // Match fingerprints:
+ // FF223344556677889900112233445566778899 or 0xFF223344556677889900112233445566778899
+ val maybeFingerprint = identifier.removePrefix("0x").takeIf {
+ it.matches("[a-fA-F0-9]{40}".toRegex())
+ }
+ if (maybeFingerprint != null) {
+ // Truncating to the long key ID is not a security issue since OpenKeychain only accepts
+ // non-ambiguous key IDs.
+ val keyId = maybeFingerprint.takeLast(16).toULong(16)
+ return GpgIdentifier.KeyId(keyId.toLong())
+ }
+
+ return OpenPgpUtils.splitUserId(identifier).email?.let { GpgIdentifier.UserId(it) }
+ }
+
/**
* Encrypts the password and the extra content
*/
- private fun encrypt(copy: Boolean = false) = with(binding) {
+ private fun encrypt(receivedIntent: Intent? = null) = with(binding) {
val editName = filename.text.toString().trim()
val editPass = password.text.toString()
val editExtra = extraContent.text.toString()
@@ -227,12 +301,25 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
copyPasswordToClipboard(editPass)
}
- val data = Intent()
+ val data = receivedIntent ?: Intent()
data.action = OpenPgpApi.ACTION_ENCRYPT
- // EXTRA_KEY_IDS requires long[]
- val longKeys = keyIDs.map { it.toLong() }
- data.putExtra(OpenPgpApi.EXTRA_KEY_IDS, longKeys.toLongArray())
+ // pass enters the key ID into `.gpg-id`.
+ val repoRoot = PasswordRepository.getRepositoryDirectory(applicationContext)
+ val gpgIdentifierFile = File(repoRoot, directory.text.toString()).findTillRoot(".gpg-id", repoRoot)
+ if (gpgIdentifierFile == null) {
+ snackbar(message = resources.getString(R.string.failed_to_find_key_id))
+ return@with
+ }
+ val gpgIdentifierFileContent = gpgIdentifierFile.useLines { it.firstOrNull() } ?: ""
+ when (val identifier = parseGpgIdentifier(gpgIdentifierFileContent)) {
+ is GpgIdentifier.KeyId -> data.putExtra(OpenPgpApi.EXTRA_KEY_IDS, arrayOf(identifier.id))
+ is GpgIdentifier.UserId -> data.putExtra(OpenPgpApi.EXTRA_USER_IDS, arrayOf(identifier.email))
+ null -> {
+ snackbar(message = resources.getString(R.string.invalid_gpg_id))
+ return@with
+ }
+ }
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true)
val content = "$editPass\n$editExtra"
@@ -347,6 +434,10 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
e(e) { "An Exception occurred" }
}
}
+ OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED -> {
+ val sender = getUserInteractionRequestIntent(result)
+ userInteractionRequiredResult.launch(IntentSenderRequest.Builder(sender).build())
+ }
OpenPgpApi.RESULT_CODE_ERROR -> handleError(result)
}
}
diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt b/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt
index 19b651b76..b274b47d0 100644
--- a/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt
+++ b/app/src/main/java/com/zeapo/pwdstore/utils/Extensions.kt
@@ -29,6 +29,8 @@ import com.zeapo.pwdstore.utils.PasswordRepository.Companion.getRepositoryDirect
import java.io.File
import org.eclipse.jgit.api.Git
+const val OPENPGP_PROVIDER = "org.sufficientlysecure.keychain"
+
fun Int.clearFlag(flag: Int): Int {
return this and flag.inv()
}
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 8b87028dd..300e03e32 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -14,7 +14,6 @@
تعديل
حذف
- لم يتم إختيار مزود الأوبن بي جي بي بعد !
الرجاء إدخال إسم ملف
جاري تنفيذ الأمر ...
@@ -54,7 +53,6 @@
إسم المستخدم :
تعديل كلمة السر
نسخ كلمة السر
- نسخ إسم المستخدم
شارك كنص مجرد
آخِر تعديل %s
@@ -64,8 +62,6 @@
إظهار مفتاح الـ SSH العمومي الذي تم توليده
حذف المستودع
تنحية المستودع
- التشفير
- إختيار مزود الأوبن بي جي بي OpenPGP
الإعدادات العامة
نسخ كلمة السر تلقائيًا
تم استيراد مفتاح الـ SSH
@@ -108,8 +104,6 @@
إظهار المزيد من المحتوى
توليد
تحديث القائمة
- إظهار كلمة السر
- إظهار المزيد من المحتوى
أيقونة التطبيق
أيقونة المجلد
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index e6c69ab34..fdb0aca3b 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -19,8 +19,6 @@
Změnit
Použít
Tento adresář je již vybrán
- OpenPGP klíč nebyl zvolen
- Přesměrujeme Vás na nastavení. Prosím, zvolte si Váš OpenPGP klíč.
Heslo již existuje!
Toto přepíše%1$s %2$s .
@@ -29,7 +27,6 @@
Upravit heslo %1$s s použítím Android Password Store.
Odstranit %1$s ze store.
- Nebyl vybrán poskytovatel OpenPGP!
Heslo zkopírováno do schránky, máte %d sekund na jeho zkopírování.
Heslo zkopírováno do schránky
Zadejte prosím jméno souboru
@@ -89,7 +86,6 @@
Jméno:
Editovat heslo
Kopírovat heslo
- Kopírovat jméno
Sdílet v nešifrované podobě
Naposled změněno %s
@@ -99,9 +95,6 @@
Zobrazit vygenerovaný veřejný SSH klíč
Smazat repozitář
Vyčistit repozitář
- Šifrování
- Vybrat poskytovatele OpenPGP
- Vybrat ID OpenPGP klíče
Všeobecné
Automaticky kopírovat heslo
Automatické kopírování hesla do schránky po úspěšném dešifrování.
@@ -159,7 +152,6 @@
Obnovit seznam
Nebyl vybrát externí repozitář
Odeslat heslo jako plaintext za použití…
- Pokaż hasło
Automaticky vyplňuje pole hesel v aplikacích. Funguje pouze pro verzi Androidu 4.3 a vyšší. Není závislé na schránce pro Android verze 5.0 a vyšší.
Použít výchozí nastavení
@@ -168,5 +160,4 @@
Spárovat s
Nikdy nepárovat
Smazat
- Failed to get last changed date
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 257d45ca4..7f1aae8be 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -17,7 +17,6 @@
Bearbeiten
Löschen
- Kein OpenPGP-Provider ausgewählt!
Passwort ist in der Zwischenablage, du hast %d Sekunden, um es einzufügen.
Bitte setze einen Pfad
Du kannst kein leeres Passwort setzen oder leere Extra-Angaben
@@ -66,7 +65,6 @@
Benutzername:
Passwort bearbeiten
Passwort kopieren
- Benutzername kopieren
Als Klartext teilen
Zuletzt geändert %s
@@ -77,9 +75,6 @@
Zeige erstellten öffentlichen SSH-Key
Repository löschen
Repository löschen
- Kryptografie
- Wähle OpenPGP-Provider
- Wähle OpenPGP-Key ID
Allgemein
Kopiere Passwort automatisch
Kopiert das Passwort in die Zwischenablage, wenn der Eintrag entschlüsselt wurde.
@@ -139,8 +134,6 @@
Aktualisieren
Kein externes Repository ausgewählt
Passwort senden als Nur-Text mit behilfe von…
- Password wiedergeben
- Zeige weiteren Inhalt
App Icon
Verzeichnis Icon
@@ -160,5 +153,4 @@
Bildschirmfoto Accessibility Services
Bildschirmfoto des Schalters in Accessibility Services
Bildschirmfoto von Autofill in Aktion
- Das Abrufen des letzten Änderungsdatums ist fehlgeschlagen.
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 4eecf6604..a1fd8725f 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -16,8 +16,6 @@
Mover
Editar
Eliminar
- No se ha seleccionado una llave OpenPGP
- Serás redirigido a los ajustes. Por favor selecciona tu llave OpenPGP.
"Contraseña para %1$s agregada usando Android Password Store."
"%1$s editada usando Android Password Store."
@@ -25,7 +23,6 @@
"Renombrado %1$s a %2$s usando Android Password Store.."
- ¡No se ha seleccionado ningún proveedor OpenGPG!
Contraseña copiada al portapapeles, tienes %d segundos para pegarla.
Contraseña copiada al portapapeles
Por favor selecciona un nombre de archivo
@@ -82,7 +79,6 @@
Nombre de usuario:
Editar contraseña
Copiar contraseña
- Copiar nombre de usuario
Compartir como texto plano
Última modificación %s
@@ -94,10 +90,6 @@
Ver llave pública SSH generada
Eliminar repositorio
Limpiar repositorio
- Cifrado
- Selecciona un proveedor OpenPGP
- Selecciona la llave OpenPGP
- Ninguna llave seleccionada
General
Copiar contraseña automáticamente
Automáticamente copia la contraseña al portapapeles si el descifrado fue exitoso.
@@ -167,8 +159,6 @@
Actualizar lista
Ningún repositorio externo seleccionado
Enviar contraseña en texto plano usando…
- Mostrar contraseña
- Mostrar contenido extra
Ícono de app
Ícono de directorio
@@ -187,7 +177,6 @@
Selecciona un campo editable para pegar el nombre de usuario.\nNombre de usuario disponible por %d segundos.
Imposible abrir la llave privada SSH. Por favor verifica que el archivo exista
Nueva contraseña
- Editando
Pantalla de Servicios de Accesibilidad
Pantalla de activación en Servicios de Accesibilidad
Pantalla de servicio de autollenado en acción
@@ -198,5 +187,4 @@
Hackish tools
Abortar rebase
Hash del commit
- Error al obtener la fecha de último cambio
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index c4c75b55a..f9ac6d516 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -20,8 +20,6 @@
Utiliser
Répertoire déjà sélectionné
Voulez-vous utiliser \"%1$s\"?
- Clé OpenPGP non sélectionnée
- Nous allons vous rediriger vers les paramètres. Veuillez sélectionner votre clé OpenPGP.
Le mot de passe existe!
Cela écrasera %1$s avec %2$s.
@@ -32,7 +30,6 @@
Renommer %1$sà %2$s.
- Aucun prestataire OpenPGP sélectionné !
Mot de passe copié dans le presse papier, vous avez %d secondes pour coller celui-ci.
Renseignez un nom de fichier
Vous ne pouvez pas utiliser un mot de passe vide ou des données supplémentaires vide
@@ -89,7 +86,6 @@
Nom d\'utilisateur
Éditer le mot de passe
Copier le mot de passe
- Copier le nom d\'utilisateur
Partager en clair
Dernière modification le %s
@@ -101,10 +97,6 @@
Voir la clef publique SSH générée
Supprimer le dépôt
Effacer le dépôt
- Chiffrement
- Sélection du prestataire OpenPGP
- Sélection de votre identifiant OpenPGP
- Aucune clé sélectionnée
Général
Copie automatique du mot de passe
Copie automatiquement le mot de passe vers le presse-papier si le déchiffrement a réussi.
@@ -167,8 +159,6 @@
Rafraichir la liste
Pas de dépôt externe séléctionné
Envoyer le mot de passe en clair via…
- Montrer le mot de passe
- Afficher le contenu supplémentaire
Icône de l\'application
Icône du dossier
@@ -186,7 +176,6 @@
Coller le nom d\'utilisateur?\n\n%s
Impossible d\'ouvrir la clef ssh, merci de vérifier que le ficher existe
Nouveau mot de passe
- Montage
Capture des services d\'accessibilité
Capture de bascule dans les services d\'accessibilité
Capture du service de remplissage automatique en action
@@ -197,5 +186,4 @@
Se rappeler de la phrase secrète dans la configuration de l\'application (peu sûr)
Outils de hack
Commettre la clé
- Failed to get last changed date
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 02dd3219b..d65de8a50 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -18,7 +18,6 @@
追加 %1$s ストアから。
編集 %1$s ストアから。
- OpenPGP プロバイダが選択されていません!
パスワードをクリップボードにコピーしました %d 秒以内に貼り付けしてください。
ファイル名を入力してください
空のパスワードを使用したり、追加のコンテンツを空にすることはできません
@@ -64,9 +63,6 @@
生成した公開 SSH 鍵を表示
リポジトリを削除
リポジトリをクリア
- 暗号化
- OpenPGP プロバイダーを選択
- OpenPGP 鍵 ID を選択
全般
自動的にパスワードをコピー
復号化が成功した後、自動的にパスワードをクリップボードにコピーします。
@@ -120,7 +116,6 @@
リストを更新
外部リポジトリが選択されていません
パスワードをプレーンテキストとして送信…
- パスワードを表示
アプリのパスワードフィールドを自動入力します。 Android バージョン 4.3 以降でのみ動作します。 Android 5.0 以降のクリップボードには依存しません。
デフォルト設定を使用する
@@ -129,5 +124,4 @@
一致
一致しない
削除
- 最終変更日の取得に失敗しました
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index ff36585b3..3b41758fa 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -20,8 +20,6 @@
Использовать
Директория уже выбрана
Вы хотите использовать \"%1$s\"?
- Ключ OpenPGP не выбран
- Мы перенаправим вас в настройки. Пожалуйста, выберите ваш OpenGPG ключ.
Пароль уже существует!
Это перезапишет %1$sна%2$s
@@ -32,7 +30,6 @@
Переименовать %1$sв%2$s.
- Не выбран провайдер OpenPGP!
Пароль скопирован в буфер обмена, у вас есть %d секунд чтобы вставить его.
Пароль скопирован в буфер обмена
Пожалуйста, укажите имя файла
@@ -94,7 +91,6 @@
Имя пользователя:
Редактировать пароль
Скопировать пароль
- Скопировать имя пользователя
Поделиться в открытом виде
Последние изменение %s
@@ -106,10 +102,6 @@
Просмотреть публичный SSH ключ
Удалить репозиторий
Очистить репозиторий
- Шифрование
- Выберите провайдера OpenPGP
- Выберите ключ OpenPGP
- Ключи не выбраны
Общие
Автоматически копировать пароль
Автоматически копировать пароль в буфер обмена после успешного расшифрования
@@ -199,9 +191,6 @@
Обновить список
Внешний репозиторий не выбран
Поделиться паролем в открытом виде с помощью
- Показать пароль
- Показать дополнительную информацию
- Скрыть расширенный контекст
Иконка приложения
Иконка папки
@@ -244,7 +233,6 @@
Выберите поле ввода для вставки имени пользователя.\nИмя пользователя можно вставить в течение %d секунд.
Невозможно открыть приватный ключ ssh, пожалуйста проверьте, что файл существует
Новый пароль
- Редактирование
Снимок экрана сервисов доступности
Снимок экрана переключателя в сервисах доступности
Снимок экрана сервиса автозаполнения в действии
@@ -258,7 +246,6 @@
Прервать перебазирование и записать изменения в новую ветку
Полный сброс до состояния удаленной ветки
Хэш-сумма изменений
- Failed to get last changed date
Ошибка при подключении к сервису OpenKeychain SSH API
Не найдено SSH API провайдеров. OpenKeychain установлен?
Ожидаемое намерение SSH API не удалось
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index 34ef46a18..8a57de7b9 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -18,7 +18,6 @@
使用Android Password Store来添加 %1$s
使用Android Password Store来修改 %1$s
- 未选择提供OpenPGP的应用
密码已复制到剪贴板, 你有 %d 秒的时间将其粘贴到其他地方.
请提供一个文件名
无法使用空白密码或者空白的额外内容
@@ -64,9 +63,6 @@
查看生成的 SSH 公钥
删除 Repo
清空 Repo
- 加密
- 选择 OpenPGP 应用
- 选择 OpenPGP Key Id
通用
自动复制密码
解密成功后自动将密码复制到剪贴板
@@ -117,7 +113,6 @@
刷新列表
未选择外部 Repo
将密码以纯文本发送…
- 显示密码
在app中自动输入密码. 此功能只在 Andorid 4.3 及以上版本中可用. 在 Andorid 5.0 及以上版本中不依赖剪贴板
使用默认设置
@@ -126,5 +121,4 @@
匹配
从不匹配
删除
- 获取上次修改日期失败
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index b38380b40..6b120faf8 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -15,7 +15,6 @@
在嘗試新增密碼或任何同步操作之前請在下方 clone 或新增一個新的 Repo
刪除
- 未選擇提供 OpenPGP 的 app
密碼已複製到剪貼簿, 你有 %d 秒的時間將其貼上到其他地方.
請填寫文件名稱
不能使用空白密碼或者空白的備註
@@ -61,9 +60,6 @@
顯示生成的 SSH 公鑰
刪除 Repo
清空 Repo
- 加密
- 選擇 OpenPGP app
- 選擇 OpenPGP Key Id
一般
自動複製密碼
解密成功後自動將密碼複製到剪貼簿
@@ -114,7 +110,6 @@
重新整理
未選擇外部 Repo
將密碼以純文字傳送…
- 顯示密碼
在app中自動填入密碼. 此功能只能在 Andorid 4.3 及以上版本中使用. 在 Andorid 5.0 及以上版本中不需要剪貼簿
使用預設值
@@ -123,5 +118,4 @@
自動填入
手動
刪除
- Failed to get last changed date
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a616896f7..0bf7f413b 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -23,7 +23,6 @@
Please clone or create a new repository below before trying to add a password or running any synchronization operation.
- A valid PGP key must be selected in Settings before initializing the repository
- Are you sure you want to delete the password?
- Are you sure you want to delete %d passwords?
@@ -35,8 +34,6 @@
Use
Directory already selected
Do you want to use \"%1$s\"?
- OpenPGP key not selected
- We will redirect you to settings. Please select your OpenPGP Key.
Password already exists!
This will overwrite %1$s with %2$s.
Error while moving passwords
@@ -50,7 +47,6 @@
Move multiple passwords to %1$s.
- No OpenPGP provider selected!
Password copied to clipboard, you have %d seconds to paste it somewhere.
Password copied to clipboard
Copied to clipboard
@@ -117,10 +113,8 @@
Username:
Edit password
Copy password
- Copy username
Share as plaintext
Last changed %s
- View OTP
Repository
@@ -131,10 +125,6 @@
View generated public SSH key
Delete repository
Clear repository
- Crypto
- Select OpenPGP provider
- Select OpenPGP key ID
- No key selected
General
Passwords
Password copy timeout
@@ -237,9 +227,6 @@
Refresh list
No external repository selected
Send password as plaintext using…
- Show password
- Show extra content
- Hide extra content
App icon
Folder icon
@@ -291,7 +278,6 @@
Select an editable field to paste the username.\nUsername is available for %d seconds.
Unable to open the ssh private key, please check that the file exists
New password
- Editing
Screenshot of accessibility services
Screenshot of toggle in accessibility services
Screenshot of autofill service in action
@@ -307,7 +293,6 @@
Abort rebase and push new branch
Hard reset to remote branch
Commit hash
- Failed to get last changed date
Failed to connect to OpenKeychain SSH API service.
No SSH API provider found. Is OpenKeychain installed?
SSH API pending intent failed
@@ -349,15 +334,12 @@
SSH key
Password
OpenKeychain
- None
Successfully saved configuration
Configuration error: %s
empty hostname
please verify your settings and try again
port must be numeric
path must be absolute (start with \'/\') when using a custom port
- Unable to open the ssh-key
- Please check that it was imported.
Wrong passphrase
Wrong password
Create new folder
@@ -390,6 +372,8 @@
Failed to import TOTP configuration
Improve reliability in Chrome
Exporting passwords…
+ Failed to locate .gpg-id, is your store set up correctly?
+ Found .gpg-id, but it did not contain a key ID, fingerprint or user ID
File name must not contain \'/\', set directory above
Directory
diff --git a/app/src/main/res/xml/preference.xml b/app/src/main/res/xml/preference.xml
index 3c39bfada..318b84311 100644
--- a/app/src/main/res/xml/preference.xml
+++ b/app/src/main/res/xml/preference.xml
@@ -78,15 +78,6 @@
app:title="@string/pref_select_external_repository" />
-
-
-
-
-