initial work on pgp activity
This commit is contained in:
parent
902cbd78b0
commit
c3eb4f0a41
7 changed files with 555 additions and 13 deletions
|
@ -68,6 +68,7 @@ dependencies {
|
|||
compile 'org.apache.commons:commons-io:1.3.2'
|
||||
compile 'com.jayway.android.robotium:robotium-solo:5.3.1'
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
||||
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
|
|
@ -84,6 +84,8 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
<activity android:name=".crypto.PgpActivity"
|
||||
android:parentActivityName=".PasswordStore"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -30,6 +30,7 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.zeapo.pwdstore.crypto.PgpActivity;
|
||||
import com.zeapo.pwdstore.crypto.PgpHandler;
|
||||
import com.zeapo.pwdstore.git.GitActivity;
|
||||
import com.zeapo.pwdstore.git.GitAsyncTask;
|
||||
|
@ -395,10 +396,11 @@ public class PasswordStore extends AppCompatActivity {
|
|||
}
|
||||
|
||||
public void decryptPassword(PasswordItem item) {
|
||||
Intent intent = new Intent(this, PgpHandler.class);
|
||||
Intent intent = new Intent(this, PgpActivity.class);
|
||||
intent.putExtra("NAME", item.toString());
|
||||
intent.putExtra("FILE_PATH", item.getFile().getAbsolutePath());
|
||||
intent.putExtra("Operation", "DECRYPT");
|
||||
intent.putExtra("REPO_PATH", PasswordRepository.getRepositoryDirectory(getApplicationContext()).getAbsolutePath());
|
||||
intent.putExtra("OPERATION", "DECRYPT");
|
||||
|
||||
// Adds shortcut
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
|
@ -459,9 +461,10 @@ public class PasswordStore extends AppCompatActivity {
|
|||
File currentDir = getCurrentDir();
|
||||
Log.i("PWDSTR", "Adding file to : " + currentDir.getAbsolutePath());
|
||||
|
||||
Intent intent = new Intent(this, PgpHandler.class);
|
||||
intent.putExtra("FILE_PATH", getCurrentDir().getAbsolutePath());
|
||||
intent.putExtra("Operation", "ENCRYPT");
|
||||
Intent intent = new Intent(this, PgpActivity.class);
|
||||
intent.putExtra("PARENT_PATH", getCurrentDir().getAbsolutePath());
|
||||
intent.putExtra("REPO_PATH", PasswordRepository.getRepositoryDirectory(getApplicationContext()).getAbsolutePath());
|
||||
intent.putExtra("OPERATION", "ENCRYPT");
|
||||
startActivityForResult(intent, PgpHandler.REQUEST_CODE_ENCRYPT);
|
||||
}
|
||||
|
||||
|
@ -620,6 +623,7 @@ public class PasswordStore extends AppCompatActivity {
|
|||
break;
|
||||
}
|
||||
|
||||
// TODO move this to an async task
|
||||
for (String string : data.getStringArrayListExtra("Files")) {
|
||||
File source = new File(string);
|
||||
if (!source.exists()) {
|
||||
|
|
533
app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
Normal file
533
app/src/main/java/com/zeapo/pwdstore/crypto/PgpActivity.kt
Normal file
|
@ -0,0 +1,533 @@
|
|||
package com.zeapo.pwdstore.crypto
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PendingIntent
|
||||
import android.content.*
|
||||
import android.graphics.Typeface
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.SystemClock
|
||||
import android.preference.PreferenceManager
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.text.TextUtils
|
||||
import android.text.method.PasswordTransformationMethod
|
||||
import android.util.Log
|
||||
import android.view.*
|
||||
import android.widget.*
|
||||
import com.zeapo.pwdstore.PasswordEntry
|
||||
import com.zeapo.pwdstore.R
|
||||
import com.zeapo.pwdstore.UserPreference
|
||||
import com.zeapo.pwdstore.pwgenDialogFragment
|
||||
import kotlinx.android.synthetic.main.decrypt_layout.*
|
||||
import kotlinx.android.synthetic.main.encrypt_layout.*
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.openintents.openpgp.IOpenPgpService2
|
||||
import org.openintents.openpgp.OpenPgpError
|
||||
import org.openintents.openpgp.util.OpenPgpApi
|
||||
import org.openintents.openpgp.util.OpenPgpApi.*
|
||||
import org.openintents.openpgp.util.OpenPgpServiceConnection
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.nio.charset.Charset
|
||||
|
||||
class PgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBound {
|
||||
val clipboard: ClipboardManager by lazy {
|
||||
getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
}
|
||||
var passwordEntry: PasswordEntry? = null
|
||||
|
||||
val name: String by lazy { intent.getStringExtra("NAME") }
|
||||
val repoPath: String by lazy { intent.getStringExtra("REPO_PATH") }
|
||||
val path: String by lazy { intent.getStringExtra("FILE_PATH") }
|
||||
val parentPath: String by lazy {
|
||||
// when encrypting we pass "PARENT_PATH" as we do not have a file
|
||||
if (operation == "ENCRYPT") intent.getStringExtra("PARENT_PATH")
|
||||
else File(path).parentFile.absolutePath
|
||||
}
|
||||
val cat: String by lazy { parentPath.replace(repoPath, "") }
|
||||
val operation: String by lazy { intent.getStringExtra("OPERATION") }
|
||||
|
||||
val settings: SharedPreferences by lazy {
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
}
|
||||
val keyIDs: MutableSet<String> by lazy {
|
||||
settings.getStringSet("openpgp_key_ids_set", emptySet())
|
||||
}
|
||||
var mServiceConnection: OpenPgpServiceConnection? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
|
||||
|
||||
// some persistence
|
||||
val providerPackageName = settings.getString("openpgp_provider_list", "")
|
||||
|
||||
if (TextUtils.isEmpty(providerPackageName)) {
|
||||
Toast.makeText(this, this.resources.getString(R.string.provider_toast_text), Toast.LENGTH_LONG).show()
|
||||
val intent = Intent(this, UserPreference::class.java)
|
||||
startActivityForResult(intent, OPEN_PGP_BOUND)
|
||||
} else {
|
||||
// bind to service
|
||||
mServiceConnection = OpenPgpServiceConnection(this, providerPackageName, this)
|
||||
mServiceConnection?.bindToService()
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
||||
when (operation) {
|
||||
"DECRYPT" -> {
|
||||
setContentView(R.layout.decrypt_layout)
|
||||
crypto_password_category_decrypt.text = "$cat/"
|
||||
crypto_password_file.text = name
|
||||
}
|
||||
"ENCRYPT" -> {
|
||||
setContentView(R.layout.encrypt_layout)
|
||||
title = getString(R.string.new_password_title)
|
||||
crypto_password_category.text = "$cat/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
mServiceConnection?.unbindFromService()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
// Do not use the value `operation` in this case as it is not valid when editing
|
||||
val menuId = when (intent.getStringExtra("OPERATION")) {
|
||||
"ENCRYPT" -> R.menu.pgp_handler_new_password
|
||||
"DECRYPT" -> R.menu.pgp_handler
|
||||
else -> R.menu.pgp_handler
|
||||
}
|
||||
|
||||
menuInflater.inflate(menuId, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
when (item?.itemId) {
|
||||
android.R.id.home -> {
|
||||
setResult(RESULT_CANCELED)
|
||||
finish()
|
||||
}
|
||||
R.id.copy_password -> copyPasswordToClipBoard()
|
||||
R.id.share_password_as_plaintext -> shareAsPlaintext()
|
||||
R.id.edit_password -> editPassword()
|
||||
R.id.crypto_confirm_add -> encrypt()
|
||||
R.id.crypto_cancel_add -> setResult(RESULT_CANCELED)
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun handleClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.generate_password -> {
|
||||
val df = pwgenDialogFragment()
|
||||
df.show(fragmentManager, "generator")
|
||||
Log.wtf(TAG, "This should not happen.... PgpHandler.java#handleClick(View) default reached.")
|
||||
}
|
||||
else -> Log.wtf(TAG, "This should not happen.... PgpHandler.java#handleClick(View) default reached.")
|
||||
}// should not happen
|
||||
}
|
||||
|
||||
|
||||
fun showToast(message: String) {
|
||||
runOnUiThread({ Toast.makeText(this, message, Toast.LENGTH_SHORT).show() })
|
||||
}
|
||||
|
||||
fun handleError(error: OpenPgpError) {
|
||||
showToast("Error from OpenKeyChain : " + error.message)
|
||||
Log.e(TAG, "onError getErrorId:" + error.errorId)
|
||||
Log.e(TAG, "onError getMessage:" + error.message)
|
||||
}
|
||||
|
||||
private fun decryptAndVerify(): Unit {
|
||||
val data = Intent()
|
||||
data.action = ACTION_DECRYPT_VERIFY
|
||||
|
||||
val iStream = FileUtils.openInputStream(File(path))
|
||||
val oStream = ByteArrayOutputStream()
|
||||
|
||||
val api = OpenPgpApi(this, mServiceConnection?.service)
|
||||
|
||||
api.executeApiAsync(data, iStream, oStream, { result: Intent? ->
|
||||
when (result?.getIntExtra(RESULT_CODE, RESULT_CODE_ERROR)) {
|
||||
RESULT_CODE_SUCCESS -> {
|
||||
try {
|
||||
val showPassword = settings.getBoolean("show_password", true)
|
||||
val showExtraContent = settings.getBoolean("show_extra_content", true)
|
||||
|
||||
crypto_container_decrypt.visibility = View.VISIBLE
|
||||
|
||||
val monoTypeface = Typeface.createFromAsset(assets, "fonts/sourcecodepro.ttf")
|
||||
val entry = PasswordEntry(oStream)
|
||||
|
||||
passwordEntry = entry
|
||||
|
||||
crypto_password_show.typeface = monoTypeface
|
||||
crypto_password_show.text = entry.password
|
||||
|
||||
crypto_password_toggle_show.visibility = if (showPassword) View.GONE else View.VISIBLE
|
||||
crypto_password_show.transformationMethod = if (showPassword) {
|
||||
null
|
||||
} else {
|
||||
HoldToShowPasswordTransformation(
|
||||
crypto_password_toggle_show,
|
||||
Runnable { crypto_password_show.text = entry.password }
|
||||
)
|
||||
}
|
||||
|
||||
if (entry.hasExtraContent()) {
|
||||
crypto_extra_show_layout.visibility = if (showExtraContent) View.VISIBLE else View.GONE
|
||||
|
||||
crypto_extra_show.typeface = monoTypeface
|
||||
crypto_extra_show.text = entry.extraContent
|
||||
|
||||
if (entry.hasUsername()) {
|
||||
crypto_username_show.visibility = View.VISIBLE
|
||||
crypto_username_show_label.visibility = View.VISIBLE
|
||||
crypto_copy_username.visibility = View.VISIBLE
|
||||
|
||||
crypto_copy_username.setOnClickListener { copyUsernameToClipBoard(entry.username) }
|
||||
crypto_username_show.typeface = monoTypeface
|
||||
crypto_username_show.text = entry.username
|
||||
} else {
|
||||
crypto_username_show.visibility = View.GONE
|
||||
crypto_username_show_label.visibility = View.GONE
|
||||
crypto_copy_username.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.getBoolean("copy_on_decrypt", true)) {
|
||||
copyPasswordToClipBoard()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "An Exception occurred", e)
|
||||
}
|
||||
}
|
||||
RESULT_CODE_USER_INTERACTION_REQUIRED -> {
|
||||
Log.i(TAG, "RESULT_CODE_USER_INTERACTION_REQUIRED")
|
||||
|
||||
val pi: PendingIntent = result.getParcelableExtra(RESULT_INTENT)
|
||||
try {
|
||||
this@PgpActivity.startIntentSenderFromChild(
|
||||
this@PgpActivity, pi.intentSender, REQUEST_DECRYPT,
|
||||
null, 0, 0, 0)
|
||||
} catch (e: IntentSender.SendIntentException) {
|
||||
Log.e(TAG, "SendIntentException", e)
|
||||
}
|
||||
}
|
||||
RESULT_CODE_ERROR -> {
|
||||
// TODO show what kind of error it is
|
||||
/* For example:
|
||||
* No suitable key found -> no key in OpenKeyChain
|
||||
*
|
||||
* Check in open-pgp-lib how their definitions and error code
|
||||
*/
|
||||
val error: OpenPgpError = result.getParcelableExtra(RESULT_ERROR)
|
||||
handleError(error)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts the password and the extra content
|
||||
*/
|
||||
private fun encrypt(): Unit {
|
||||
val name = crypto_password_file_edit.text.toString()
|
||||
val pass = crypto_password_edit.text.toString()
|
||||
val extra = crypto_extra_edit.text.toString()
|
||||
|
||||
if (name.isEmpty()) {
|
||||
showToast(resources.getString(R.string.file_toast_text))
|
||||
return
|
||||
}
|
||||
|
||||
if (pass.isEmpty() && extra.isEmpty()) {
|
||||
showToast(resources.getString(R.string.empty_toast_text))
|
||||
return
|
||||
}
|
||||
|
||||
val data = 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())
|
||||
data.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true)
|
||||
|
||||
// TODO Check if we could use PasswordEntry to generate the file
|
||||
val iStream = ByteArrayInputStream("$pass\n$extra".toByteArray(Charset.forName("UTF-8")))
|
||||
val oStream = ByteArrayOutputStream()
|
||||
|
||||
val api = OpenPgpApi(this, mServiceConnection?.service)
|
||||
val path = "$parentPath/$name.gpg"
|
||||
|
||||
api.executeApiAsync(data, iStream, oStream, { result: Intent? ->
|
||||
when (result?.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
|
||||
OpenPgpApi.RESULT_CODE_SUCCESS -> {
|
||||
try {
|
||||
// TODO This might fail, we should check that the write is successful
|
||||
val outputStream = FileUtils.openOutputStream(File(path))
|
||||
outputStream.write(oStream.toByteArray())
|
||||
outputStream.close()
|
||||
|
||||
val returnIntent = Intent()
|
||||
returnIntent.putExtra("CREATED_FILE", path)
|
||||
returnIntent.putExtra("NAME", name)
|
||||
|
||||
// if coming from decrypt screen->edit button
|
||||
if (intent.getBooleanExtra("fromDecrypt", false)) {
|
||||
data.putExtra("needCommit", true)
|
||||
}
|
||||
|
||||
setResult(RESULT_OK, returnIntent)
|
||||
finish()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "An Exception occurred", e)
|
||||
}
|
||||
}
|
||||
OpenPgpApi.RESULT_CODE_ERROR -> {
|
||||
// TODO show what kind of error it is
|
||||
/* For example:
|
||||
* No suitable key found -> no key in OpenKeyChain
|
||||
*
|
||||
* Check in open-pgp-lib how their definitions and error code
|
||||
*/
|
||||
val error: OpenPgpError = result.getParcelableExtra(OpenPgpApi.RESULT_ERROR)
|
||||
handleError(error)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens EncryptActivity with the information for this file to be edited
|
||||
*/
|
||||
fun editPassword() {
|
||||
setContentView(R.layout.encrypt_layout)
|
||||
|
||||
title = getString(R.string.edit_password_title)
|
||||
|
||||
val monoTypeface = Typeface.createFromAsset(assets, "fonts/sourcecodepro.ttf")
|
||||
crypto_password_edit.setText(passwordEntry?.password)
|
||||
crypto_password_edit.typeface = monoTypeface
|
||||
crypto_extra_edit.setText(passwordEntry?.extraContent)
|
||||
crypto_extra_edit.typeface = monoTypeface
|
||||
|
||||
crypto_password_category.text = "$cat/"
|
||||
crypto_password_file_edit.setText(name)
|
||||
crypto_password_file_edit.isEnabled = false
|
||||
|
||||
delayTask?.skip = true
|
||||
|
||||
val data = Intent(this, PgpActivity::class.java)
|
||||
data.putExtra("OPERATION", "ENCRYPT")
|
||||
data.putExtra("fromDecrypt", true)
|
||||
intent = data
|
||||
invalidateOptionsMenu()
|
||||
|
||||
}
|
||||
|
||||
override fun onError(e: Exception?) {}
|
||||
|
||||
/**
|
||||
* The action to take when the PGP service is bound
|
||||
*/
|
||||
override fun onBound(service: IOpenPgpService2?) {
|
||||
if (operation == "DECRYPT") decryptAndVerify()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
Log.d(TAG, "onActivityResult resultCode: " + resultCode)
|
||||
|
||||
if (data == null) {
|
||||
setResult(Activity.RESULT_CANCELED, null)
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
// try again after user interaction
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
when (requestCode) {
|
||||
REQUEST_DECRYPT -> decryptAndVerify()
|
||||
else -> {
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
} else if (resultCode == Activity.RESULT_CANCELED) {
|
||||
setResult(Activity.RESULT_CANCELED, data)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class HoldToShowPasswordTransformation constructor(button: Button, private val onToggle: Runnable) :
|
||||
PasswordTransformationMethod(), View.OnTouchListener {
|
||||
private var shown = false
|
||||
|
||||
init {
|
||||
button.setOnTouchListener(this)
|
||||
}
|
||||
|
||||
override fun getTransformation(charSequence: CharSequence, view: View): CharSequence {
|
||||
return if (shown) charSequence else super.getTransformation("12345", view)
|
||||
}
|
||||
|
||||
override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
|
||||
when (motionEvent.action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
shown = true
|
||||
onToggle.run()
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
shown = false
|
||||
onToggle.run()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
fun copyPasswordToClipBoard() {
|
||||
|
||||
if (findViewById(R.id.crypto_password_show) == null)
|
||||
return
|
||||
|
||||
setTimer()
|
||||
|
||||
val clip = ClipData.newPlainText("pgp_handler_result_pm", passwordEntry?.password)
|
||||
clipboard.primaryClip = clip
|
||||
|
||||
var clearAfter = 45
|
||||
try {
|
||||
clearAfter = Integer.parseInt(settings.getString("general_show_time", "45"))
|
||||
} catch (e: NumberFormatException) {
|
||||
// ignore and keep default
|
||||
}
|
||||
|
||||
showToast(this.resources.getString(R.string.clipboard_password_toast_text, clearAfter))
|
||||
}
|
||||
|
||||
fun copyUsernameToClipBoard(username: String) {
|
||||
val clip = ClipData.newPlainText("pgp_handler_result_pm", username)
|
||||
clipboard.primaryClip = clip
|
||||
showToast(resources.getString(R.string.clipboard_username_toast_text))
|
||||
}
|
||||
|
||||
|
||||
fun shareAsPlaintext() {
|
||||
if (findViewById(R.id.share_password_as_plaintext) == null)
|
||||
return
|
||||
|
||||
val sendIntent = Intent()
|
||||
sendIntent.action = Intent.ACTION_SEND
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, passwordEntry?.password)
|
||||
sendIntent.type = "text/plain"
|
||||
startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.send_plaintext_password_to)))//Always show a picker to give the user a chance to cancel
|
||||
}
|
||||
|
||||
fun setTimer() {
|
||||
delayTask?.skip = true
|
||||
|
||||
// launch a new one
|
||||
delayTask = DelayShow(this)
|
||||
delayTask?.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
|
||||
}
|
||||
|
||||
inner class DelayShow(val activity: PgpActivity) : AsyncTask<Void, Int, Boolean>() {
|
||||
internal val pb: ProgressBar by lazy { pbLoading }
|
||||
internal var skip = false
|
||||
internal var showTime: Int = 0
|
||||
|
||||
val settings: SharedPreferences by lazy {
|
||||
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
}
|
||||
|
||||
override fun onPreExecute() {
|
||||
try {
|
||||
showTime = Integer.parseInt(settings.getString("general_show_time", "45"))
|
||||
} catch (e: NumberFormatException) {
|
||||
showTime = 45
|
||||
}
|
||||
|
||||
val container = findViewById(R.id.crypto_container_decrypt) as LinearLayout
|
||||
container.visibility = View.VISIBLE
|
||||
|
||||
val extraText = findViewById(R.id.crypto_extra_show) as TextView
|
||||
|
||||
if (extraText.text.isNotEmpty())
|
||||
findViewById(R.id.crypto_extra_show_layout).visibility = View.VISIBLE
|
||||
|
||||
if (showTime == 0) {
|
||||
// treat 0 as forever, and the user must exit and/or clear clipboard on their own
|
||||
cancel(true)
|
||||
} else {
|
||||
this.pb.max = showTime
|
||||
}
|
||||
}
|
||||
|
||||
override fun doInBackground(vararg params: Void): Boolean? {
|
||||
var current = 0
|
||||
while (current < showTime) {
|
||||
SystemClock.sleep(1000)
|
||||
current++
|
||||
publishProgress(current)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPostExecute(b: Boolean?) {
|
||||
if (skip) return
|
||||
|
||||
// only clear the clipboard if we automatically copied the password to it
|
||||
if (settings.getBoolean("copy_on_decrypt", true)) {
|
||||
Log.d("DELAY_SHOW", "Clearing the clipboard")
|
||||
val clip = ClipData.newPlainText("pgp_handler_result_pm", "")
|
||||
clipboard.primaryClip = clip
|
||||
if (settings.getBoolean("clear_clipboard_20x", false)) {
|
||||
val handler = Handler()
|
||||
for (i in 0..18) {
|
||||
val count = i.toString()
|
||||
handler.postDelayed({ clipboard.primaryClip = ClipData.newPlainText(count, count) }, (i * 500).toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (crypto_password_show != null) {
|
||||
passwordEntry = null
|
||||
// clear password; if decrypt changed to encrypt layout via edit button, no need
|
||||
crypto_password_show.text = ""
|
||||
crypto_extra_show.text = ""
|
||||
crypto_extra_show_layout.visibility = View.INVISIBLE
|
||||
crypto_container_decrypt.visibility = View.INVISIBLE
|
||||
setResult(Activity.RESULT_CANCELED)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgressUpdate(vararg values: Int?) {
|
||||
this.pb.progress = values[0] ?: 0
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val OPEN_PGP_BOUND = 101
|
||||
val REQUEST_EDIT = 201
|
||||
val REQUEST_DECRYPT = 202
|
||||
|
||||
val TAG = "PgpActivity"
|
||||
|
||||
private var delayTask: DelayShow? = null
|
||||
}
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ public class PgpHandler extends AppCompatActivity implements OpenPgpServiceConne
|
|||
|| findViewById(R.id.crypto_container).getVisibility() != View.VISIBLE)
|
||||
return;
|
||||
|
||||
CharSequence category = ((TextView) findViewById(R.id.crypto_password_category)).getText();
|
||||
CharSequence category = ((TextView) findViewById(R.id.crypto_password_category_decrypt)).getText();
|
||||
CharSequence file = ((TextView) findViewById(R.id.crypto_password_file)).getText();
|
||||
CharSequence password = ((TextView) findViewById(R.id.crypto_password_show)).getText();
|
||||
CharSequence extra = ((TextView) findViewById(R.id.crypto_extra_show)).getText();
|
||||
|
@ -211,7 +211,7 @@ public class PgpHandler extends AppCompatActivity implements OpenPgpServiceConne
|
|||
((EditText) findViewById(R.id.crypto_password_edit)).setTypeface(monoTypeface);
|
||||
((EditText) findViewById(R.id.crypto_extra_edit)).setTypeface(monoTypeface);
|
||||
|
||||
((TextView) findViewById(R.id.crypto_password_category)).setText(category);
|
||||
((TextView) findViewById(R.id.crypto_password_category_decrypt)).setText(category);
|
||||
((EditText) findViewById(R.id.crypto_password_file_edit)).setText(file);
|
||||
((EditText) findViewById(R.id.crypto_password_edit)).setText(password);
|
||||
((EditText) findViewById(R.id.crypto_extra_edit)).setText(extra);
|
||||
|
@ -748,7 +748,7 @@ public class PgpHandler extends AppCompatActivity implements OpenPgpServiceConne
|
|||
.replace(PasswordRepository.getRepositoryDirectory(getApplicationContext()).getAbsolutePath(), "");
|
||||
String cat = new File(path).getParentFile().getName();
|
||||
|
||||
((TextView) findViewById(R.id.crypto_password_category)).setText(cat + "/");
|
||||
((TextView) findViewById(R.id.crypto_password_category_decrypt)).setText(cat + "/");
|
||||
decryptAndVerify(new Intent());
|
||||
break;
|
||||
}
|
||||
|
@ -760,7 +760,7 @@ public class PgpHandler extends AppCompatActivity implements OpenPgpServiceConne
|
|||
String cat = extra.getString("FILE_PATH");
|
||||
cat = cat.replace(PasswordRepository.getRepositoryDirectory(getApplicationContext()).getAbsolutePath(), "");
|
||||
cat = cat + "/";
|
||||
((TextView) findViewById(R.id.crypto_password_category)).setText(cat);
|
||||
((TextView) findViewById(R.id.crypto_password_category_decrypt)).setText(cat);
|
||||
break;
|
||||
}
|
||||
case "GET_KEY_ID":
|
||||
|
@ -778,7 +778,7 @@ public class PgpHandler extends AppCompatActivity implements OpenPgpServiceConne
|
|||
String cat = new File(extra.getString("FILE_PATH").replace(PasswordRepository.getRepositoryDirectory(getApplicationContext()).getAbsolutePath(), ""))
|
||||
.getParentFile().getName();
|
||||
|
||||
((TextView) findViewById(R.id.crypto_password_category)).setText(cat + "/");
|
||||
((TextView) findViewById(R.id.crypto_password_category_decrypt)).setText(cat + "/");
|
||||
edit(new Intent());
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/crypto_password_category"
|
||||
android:id="@+id/crypto_password_category_decrypt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
@ -54,7 +54,7 @@
|
|||
tools:ignore="ContentDescription" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/crypto_container"
|
||||
android:id="@+id/crypto_container_decrypt"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -199,6 +199,8 @@
|
|||
<string name="autofill_paste_username">Paste username?\n\n%s</string>
|
||||
<string name="autofill_toast_username">Select an editable field to past the username.\nUsername is available for %d seconds.</string>
|
||||
<string name="ssh_key_does_not_exist">Unable to open the ssh private key, please check that the file exists</string>
|
||||
<string name="new_password_title">New password</string>
|
||||
<string name="edit_password_title">Editing</string>
|
||||
<string name="autofill_ins_1_hint">Screenshot of accessibility services</string>
|
||||
<string name="autofill_ins_2_hint">Screenshot of toggle in accessibility services</string>
|
||||
<string name="autofill_ins_3_hint">Screenshot of autofill service in action</string>
|
||||
|
|
Loading…
Reference in a new issue