aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
diff options
context:
space:
mode:
authorHarsh Shandilya <me@msfjarvis.dev>2020-12-05 06:07:18 +0530
committerGitHub <noreply@github.com>2020-12-05 06:07:18 +0530
commit5e66d99c852ea67a88b650c03b0e8d55e83eccde (patch)
treeaee323a08253fe7b863976eff92a1bd412bd1430 /app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
parent8eb55f18a11d6b2f155c7c9d48ca833313ee13db (diff)
downloadHardenedPass-5e66d99c852ea67a88b650c03b0e8d55e83eccde.tar.gz
HardenedPass-5e66d99c852ea67a88b650c03b0e8d55e83eccde.zip
Refactor package structure (#1233)
* idea: default test runner to Gradle * Kick off package structure revamp * Reparent all classes under dev.msfjarvis.aps Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Diffstat (limited to 'app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt')
-rw-r--r--app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt260
1 files changed, 0 insertions, 260 deletions
diff --git a/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt b/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
deleted file mode 100644
index cfcecc22..00000000
--- a/app/src/main/java/com/zeapo/pwdstore/crypto/DecryptActivity.kt
+++ /dev/null
@@ -1,260 +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.graphics.Typeface
-import android.os.Bundle
-import android.text.method.PasswordTransformationMethod
-import android.view.Menu
-import android.view.MenuItem
-import android.view.View
-import androidx.activity.result.IntentSenderRequest
-import androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult
-import androidx.lifecycle.lifecycleScope
-import com.github.ajalt.timberkt.e
-import com.github.michaelbull.result.onFailure
-import com.github.michaelbull.result.runCatching
-import com.zeapo.pwdstore.R
-import com.zeapo.pwdstore.databinding.DecryptLayoutBinding
-import com.zeapo.pwdstore.model.PasswordEntry
-import com.zeapo.pwdstore.utils.PreferenceKeys
-import com.zeapo.pwdstore.utils.viewBinding
-import java.io.ByteArrayOutputStream
-import java.io.File
-import kotlin.time.ExperimentalTime
-import kotlin.time.seconds
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import me.msfjarvis.openpgpktx.util.OpenPgpApi
-import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
-import org.openintents.openpgp.IOpenPgpService2
-
-class DecryptActivity : BasePgpActivity(), OpenPgpServiceConnection.OnBound {
-
- private val binding by viewBinding(DecryptLayoutBinding::inflate)
-
- private val relativeParentPath by lazy(LazyThreadSafetyMode.NONE) { getParentPath(fullPath, repoPath) }
- private var passwordEntry: PasswordEntry? = null
-
- private val userInteractionRequiredResult = registerForActivityResult(StartIntentSenderForResult()) { result ->
- if (result.data == null) {
- setResult(RESULT_CANCELED, null)
- finish()
- return@registerForActivityResult
- }
-
- when (result.resultCode) {
- RESULT_OK -> decryptAndVerify(result.data)
- RESULT_CANCELED -> {
- setResult(RESULT_CANCELED, result.data)
- finish()
- }
- }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- bindToOpenKeychain(this)
- title = name
- with(binding) {
- setContentView(root)
- passwordCategory.text = relativeParentPath
- passwordFile.text = name
- passwordFile.setOnLongClickListener {
- copyTextToClipboard(name)
- true
- }
- passwordLastChanged.run {
- runCatching {
- text = resources.getString(R.string.last_changed, lastChangedString)
- }.onFailure {
- visibility = View.GONE
- }
- }
- }
- }
-
- override fun onCreateOptionsMenu(menu: Menu?): Boolean {
- menuInflater.inflate(R.menu.pgp_handler, menu)
- passwordEntry?.let { entry ->
- if (menu != null) {
- menu.findItem(R.id.edit_password).isVisible = true
- if (entry.password.isNotEmpty()) {
- menu.findItem(R.id.share_password_as_plaintext).isVisible = true
- menu.findItem(R.id.copy_password).isVisible = true
- }
- }
- }
- return true
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- android.R.id.home -> onBackPressed()
- R.id.edit_password -> editPassword()
- R.id.share_password_as_plaintext -> shareAsPlaintext()
- R.id.copy_password -> copyPasswordToClipboard(passwordEntry?.password)
- }
- return super.onOptionsItemSelected(item)
- }
-
- override fun onBound(service: IOpenPgpService2) {
- super.onBound(service)
- decryptAndVerify()
- }
-
- override fun onError(e: Exception) {
- e(e)
- }
-
- /**
- * Automatically finishes the activity 60 seconds after decryption succeeded to prevent
- * information leaks from stale activities.
- */
- @OptIn(ExperimentalTime::class)
- private fun startAutoDismissTimer() {
- lifecycleScope.launch {
- delay(60.seconds)
- finish()
- }
- }
-
- /**
- * Edit the current password and hide all the fields populated by encrypted data so that when
- * the result triggers they can be repopulated with new data.
- */
- private fun editPassword() {
- val intent = Intent(this, PasswordCreationActivity::class.java)
- intent.putExtra("FILE_PATH", relativeParentPath)
- intent.putExtra("REPO_PATH", repoPath)
- intent.putExtra(PasswordCreationActivity.EXTRA_FILE_NAME, name)
- intent.putExtra(PasswordCreationActivity.EXTRA_PASSWORD, passwordEntry?.password)
- intent.putExtra(PasswordCreationActivity.EXTRA_EXTRA_CONTENT, passwordEntry?.extraContent)
- intent.putExtra(PasswordCreationActivity.EXTRA_EDITING, true)
- startActivity(intent)
- finish()
- }
-
- private fun shareAsPlaintext() {
- val sendIntent = Intent().apply {
- action = Intent.ACTION_SEND
- putExtra(Intent.EXTRA_TEXT, passwordEntry?.password)
- type = "text/plain"
- }
- // Always show a picker to give the user a chance to cancel
- startActivity(Intent.createChooser(sendIntent, resources.getText(R.string.send_plaintext_password_to)))
- }
-
- @OptIn(ExperimentalTime::class)
- private fun decryptAndVerify(receivedIntent: Intent? = null) {
- if (api == null) {
- bindToOpenKeychain(this)
- return
- }
- val data = receivedIntent ?: Intent()
- data.action = OpenPgpApi.ACTION_DECRYPT_VERIFY
-
- val inputStream = File(fullPath).inputStream()
- val outputStream = ByteArrayOutputStream()
-
- lifecycleScope.launch(Dispatchers.IO) {
- api?.executeApiAsync(data, inputStream, outputStream) { result ->
- when (result?.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {
- OpenPgpApi.RESULT_CODE_SUCCESS -> {
- startAutoDismissTimer()
- runCatching {
- val showPassword = settings.getBoolean(PreferenceKeys.SHOW_PASSWORD, true)
- val showExtraContent = settings.getBoolean(PreferenceKeys.SHOW_EXTRA_CONTENT, true)
- val monoTypeface = Typeface.createFromAsset(assets, "fonts/sourcecodepro.ttf")
- val entry = PasswordEntry(outputStream)
-
- passwordEntry = entry
- invalidateOptionsMenu()
-
- with(binding) {
- if (entry.password.isEmpty()) {
- passwordTextContainer.visibility = View.GONE
- } else {
- passwordTextContainer.visibility = View.VISIBLE
- passwordText.typeface = monoTypeface
- passwordText.setText(entry.password)
- if (!showPassword) {
- passwordText.transformationMethod = PasswordTransformationMethod.getInstance()
- }
- passwordTextContainer.setOnClickListener { copyPasswordToClipboard(entry.password) }
- passwordText.setOnClickListener { copyPasswordToClipboard(entry.password) }
- }
-
- if (entry.hasExtraContent()) {
- if (entry.extraContentWithoutAuthData.isNotEmpty()) {
- extraContentContainer.visibility = View.VISIBLE
- extraContent.typeface = monoTypeface
- extraContent.setText(entry.extraContentWithoutAuthData)
- if (!showExtraContent) {
- extraContent.transformationMethod = PasswordTransformationMethod.getInstance()
- }
- extraContentContainer.setOnClickListener { copyTextToClipboard(entry.extraContentWithoutAuthData) }
- extraContent.setOnClickListener { copyTextToClipboard(entry.extraContentWithoutAuthData) }
- }
-
- if (entry.hasUsername()) {
- usernameText.typeface = monoTypeface
- usernameText.setText(entry.username)
- usernameTextContainer.setEndIconOnClickListener { copyTextToClipboard(entry.username) }
- usernameTextContainer.visibility = View.VISIBLE
- } else {
- usernameTextContainer.visibility = View.GONE
- }
-
- if (entry.hasTotp()) {
- otpTextContainer.visibility = View.VISIBLE
- otpTextContainer.setEndIconOnClickListener {
- copyTextToClipboard(
- otpText.text.toString(),
- snackbarTextRes = R.string.clipboard_otp_copied_text
- )
- }
- launch(Dispatchers.IO) {
- // Calculate the actual remaining time for the first pass
- // then return to the standard 30 second affair.
- val remainingTime = entry.totpPeriod - (System.currentTimeMillis() % entry.totpPeriod)
- withContext(Dispatchers.Main) {
- otpText.setText(entry.calculateTotpCode()
- ?: "Error")
- }
- delay(remainingTime.seconds)
- repeat(Int.MAX_VALUE) {
- val code = entry.calculateTotpCode() ?: "Error"
- withContext(Dispatchers.Main) {
- otpText.setText(code)
- }
- delay(30.seconds)
- }
- }
- }
- }
- }
-
- if (settings.getBoolean(PreferenceKeys.COPY_ON_DECRYPT, false)) {
- copyPasswordToClipboard(entry.password)
- }
- }.onFailure { e ->
- e(e)
- }
- }
- OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED -> {
- val sender = getUserInteractionRequestIntent(result)
- userInteractionRequiredResult.launch(IntentSenderRequest.Builder(sender).build())
- }
- OpenPgpApi.RESULT_CODE_ERROR -> handleError(result)
- }
- }
- }
- }
-}