Replace Timber with logcat (#1509)

* Replace Timber with logcat (#1505)

* Add extension for asLog which takes a message param

Co-authored-by: Aditya Wasan <adityawasan55@gmail.com>
This commit is contained in:
(´⌣`ʃƪ) 2021-10-03 01:32:15 -07:00 committed by GitHub
parent c4df226cfd
commit 2cef6a5bb4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 247 additions and 196 deletions

View file

@ -107,12 +107,11 @@ dependencies {
exclude(group = "org.apache.httpcomponents", module = "httpclient")
}
implementation(libs.thirdparty.kotlinResult)
implementation(libs.thirdparty.logcat)
implementation(libs.thirdparty.modernAndroidPrefs)
implementation(libs.thirdparty.plumber)
implementation(libs.thirdparty.sshauth)
implementation(libs.thirdparty.sshj)
implementation(libs.thirdparty.timber)
implementation(libs.thirdparty.timberkt)
if (isSnapshot()) {
implementation(libs.thirdparty.whatthestack)

View file

@ -13,8 +13,6 @@ import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import com.github.ajalt.timberkt.Timber.DebugTree
import com.github.ajalt.timberkt.Timber.plant
import dagger.hilt.android.HiltAndroidApp
import dev.msfjarvis.aps.injection.context.FilesDirPath
import dev.msfjarvis.aps.injection.prefs.SettingsPreferences
@ -25,6 +23,7 @@ import dev.msfjarvis.aps.util.settings.GitSettings
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import dev.msfjarvis.aps.util.settings.runMigrations
import javax.inject.Inject
import logcat.AndroidLogcatLogger
@Suppress("Unused")
@HiltAndroidApp
@ -41,7 +40,7 @@ class Application : android.app.Application(), SharedPreferences.OnSharedPrefere
if (BuildConfig.ENABLE_DEBUG_FEATURES ||
prefs.getBoolean(PreferenceKeys.ENABLE_DEBUG_LOGGING, false)
) {
plant(DebugTree())
AndroidLogcatLogger.installOnDebuggableApp(this)
StrictMode.setVmPolicy(VmPolicy.Builder().detectAll().penaltyLog().build())
StrictMode.setThreadPolicy(ThreadPolicy.Builder().detectAll().penaltyLog().build())
}

View file

@ -17,8 +17,6 @@ import androidx.activity.result.contract.ActivityResultContracts.StartIntentSend
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.AutofillAction
import com.github.androidpasswordstore.autofillparser.Credentials
import com.github.michaelbull.result.getOrElse
@ -31,6 +29,7 @@ import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.AutofillResponseBuilder
import dev.msfjarvis.aps.util.autofill.DirectoryStructure
import dev.msfjarvis.aps.util.extensions.OPENPGP_PROVIDER
import dev.msfjarvis.aps.util.extensions.asLog
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.InputStream
@ -43,6 +42,9 @@ import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
import me.msfjarvis.openpgpktx.util.OpenPgpApi
import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
import org.openintents.openpgp.IOpenPgpService2
@ -108,21 +110,21 @@ class AutofillDecryptActivity : AppCompatActivity() {
val filePath =
intent?.getStringExtra(EXTRA_FILE_PATH)
?: run {
e { "AutofillDecryptActivity started without EXTRA_FILE_PATH" }
logcat(ERROR) { "AutofillDecryptActivity started without EXTRA_FILE_PATH" }
finish()
return
}
val clientState =
intent?.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE)
?: run {
e { "AutofillDecryptActivity started without EXTRA_CLIENT_STATE" }
logcat(ERROR) { "AutofillDecryptActivity started without EXTRA_CLIENT_STATE" }
finish()
return
}
val isSearchAction = intent?.getBooleanExtra(EXTRA_SEARCH_ACTION, true)!!
val action = if (isSearchAction) AutofillAction.Search else AutofillAction.Match
directoryStructure = AutofillPreferences.directoryStructure(this)
d { action.toString() }
logcat { action.toString() }
lifecycleScope.launch {
val credentials = decryptCredential(File(filePath))
if (credentials == null) {
@ -183,14 +185,14 @@ class AutofillDecryptActivity : AppCompatActivity() {
val command = resumeIntent ?: Intent().apply { action = OpenPgpApi.ACTION_DECRYPT_VERIFY }
runCatching { file.inputStream() }
.onFailure { e ->
e(e) { "File to decrypt not found" }
logcat(ERROR) { e.asLog("File to decrypt not found") }
return null
}
.onSuccess { encryptedInput ->
val decryptedOutput = ByteArrayOutputStream()
runCatching { executeOpenPgpApi(command, encryptedInput, decryptedOutput) }
.onFailure { e ->
e(e) { "OpenPgpApi ACTION_DECRYPT_VERIFY failed" }
logcat(ERROR) { e.asLog("OpenPgpApi ACTION_DECRYPT_VERIFY failed") }
return null
}
.onSuccess { result ->
@ -212,7 +214,7 @@ class AutofillDecryptActivity : AppCompatActivity() {
)
}
.getOrElse { e ->
e(e) { "Failed to parse password entry" }
logcat(ERROR) { e.asLog("Failed to parse password entry") }
return null
}
}
@ -232,7 +234,9 @@ class AutofillDecryptActivity : AppCompatActivity() {
decryptCredential(file, intentToResume)
}
.getOrElse { e ->
e(e) { "OpenPgpApi ACTION_DECRYPT_VERIFY failed with user interaction" }
logcat(ERROR) {
e.asLog("OpenPgpApi ACTION_DECRYPT_VERIFY failed with user interaction")
}
return null
}
}
@ -247,14 +251,14 @@ class AutofillDecryptActivity : AppCompatActivity() {
)
.show()
}
e {
logcat(ERROR) {
"OpenPgpApi ACTION_DECRYPT_VERIFY failed (${error.errorId}): ${error.message}"
}
}
null
}
else -> {
e { "Unrecognized OpenPgpApi result: $resultCode" }
logcat(ERROR) { "Unrecognized OpenPgpApi result: $resultCode" }
null
}
}

View file

@ -14,8 +14,6 @@ import android.view.autofill.AutofillManager
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.AutofillAction
import com.github.androidpasswordstore.autofillparser.Credentials
import com.github.michaelbull.result.getOrElse
@ -29,11 +27,15 @@ import dev.msfjarvis.aps.ui.crypto.DecryptActivityV2
import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.AutofillResponseBuilder
import dev.msfjarvis.aps.util.autofill.DirectoryStructure
import dev.msfjarvis.aps.util.extensions.asLog
import java.io.File
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
@AndroidEntryPoint
@ -80,21 +82,21 @@ class AutofillDecryptActivityV2 : AppCompatActivity() {
val filePath =
intent?.getStringExtra(EXTRA_FILE_PATH)
?: run {
e { "AutofillDecryptActivityV2 started without EXTRA_FILE_PATH" }
logcat(ERROR) { "AutofillDecryptActivityV2 started without EXTRA_FILE_PATH" }
finish()
return
}
val clientState =
intent?.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE)
?: run {
e { "AutofillDecryptActivityV2 started without EXTRA_CLIENT_STATE" }
logcat(ERROR) { "AutofillDecryptActivityV2 started without EXTRA_CLIENT_STATE" }
finish()
return
}
val isSearchAction = intent?.getBooleanExtra(EXTRA_SEARCH_ACTION, true)!!
val action = if (isSearchAction) AutofillAction.Search else AutofillAction.Match
directoryStructure = AutofillPreferences.directoryStructure(this)
d { action.toString() }
logcat { action.toString() }
lifecycleScope.launch {
val credentials = decryptCredential(File(filePath))
if (credentials == null) {
@ -121,7 +123,7 @@ class AutofillDecryptActivityV2 : AppCompatActivity() {
private suspend fun decryptCredential(file: File): Credentials? {
runCatching { file.inputStream() }
.onFailure { e ->
e(e) { "File to decrypt not found" }
logcat(ERROR) { e.asLog("File to decrypt not found") }
return null
}
.onSuccess { encryptedInput ->
@ -136,7 +138,7 @@ class AutofillDecryptActivityV2 : AppCompatActivity() {
}
}
.onFailure { e ->
e(e) { "Decryption failed" }
logcat(ERROR) { e.asLog("Decryption failed") }
return null
}
.onSuccess { result ->
@ -145,7 +147,7 @@ class AutofillDecryptActivityV2 : AppCompatActivity() {
AutofillPreferences.credentialsFromStoreEntry(this, file, entry, directoryStructure)
}
.getOrElse { e ->
e(e) { "Failed to parse password entry" }
logcat(ERROR) { e.asLog("Failed to parse password entry") }
return null
}
}

View file

@ -24,7 +24,6 @@ import androidx.core.widget.addTextChangedListener
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.FormOrigin
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.data.password.PasswordItem
@ -39,6 +38,8 @@ import dev.msfjarvis.aps.util.viewmodel.ListMode
import dev.msfjarvis.aps.util.viewmodel.SearchMode
import dev.msfjarvis.aps.util.viewmodel.SearchableRepositoryAdapter
import dev.msfjarvis.aps.util.viewmodel.SearchableRepositoryViewModel
import logcat.LogPriority.ERROR
import logcat.logcat
@TargetApi(Build.VERSION_CODES.O)
class AutofillFilterView : AppCompatActivity() {
@ -102,7 +103,7 @@ class AutofillFilterView : AppCompatActivity() {
window.attributes = params
if (intent?.hasExtra(AutofillManager.EXTRA_CLIENT_STATE) != true) {
e { "AutofillFilterActivity started without EXTRA_CLIENT_STATE" }
logcat(ERROR) { "AutofillFilterActivity started without EXTRA_CLIENT_STATE" }
finish()
return
}
@ -115,7 +116,7 @@ class AutofillFilterView : AppCompatActivity() {
FormOrigin.App(intent!!.getStringExtra(EXTRA_FORM_ORIGIN_APP)!!)
}
else -> {
e {
logcat(ERROR) {
"AutofillFilterActivity started without EXTRA_FORM_ORIGIN_WEB or EXTRA_FORM_ORIGIN_APP"
}
finish()

View file

@ -17,7 +17,6 @@ import android.text.format.DateUtils
import android.view.View
import android.view.autofill.AutofillManager
import androidx.appcompat.app.AppCompatActivity
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.FormOrigin
import com.github.androidpasswordstore.autofillparser.computeCertificatesHash
import com.github.michaelbull.result.onFailure
@ -26,7 +25,10 @@ import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.databinding.ActivityOreoAutofillPublisherChangedBinding
import dev.msfjarvis.aps.util.autofill.AutofillMatcher
import dev.msfjarvis.aps.util.autofill.AutofillPublisherChangedException
import dev.msfjarvis.aps.util.extensions.asLog
import dev.msfjarvis.aps.util.extensions.viewBinding
import logcat.LogPriority.ERROR
import logcat.logcat
@TargetApi(Build.VERSION_CODES.O)
class AutofillPublisherChangedActivity : AppCompatActivity() {
@ -69,7 +71,7 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
appPackage =
intent.getStringExtra(EXTRA_APP_PACKAGE)
?: run {
e { "AutofillPublisherChangedActivity started without EXTRA_PACKAGE_NAME" }
logcat(ERROR) { "AutofillPublisherChangedActivity started without EXTRA_PACKAGE_NAME" }
finish()
return
}
@ -117,7 +119,7 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
}
}
.onFailure { e ->
e(e) { "Failed to retrieve package info for $appPackage" }
logcat(ERROR) { e.asLog("Failed to retrieve package info for $appPackage") }
finish()
}
}

View file

@ -15,7 +15,6 @@ import androidx.activity.result.contract.ActivityResultContracts.StartActivityFo
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.AutofillAction
import com.github.androidpasswordstore.autofillparser.Credentials
import com.github.androidpasswordstore.autofillparser.FormOrigin
@ -26,6 +25,8 @@ import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.AutofillResponseBuilder
import dev.msfjarvis.aps.util.extensions.unsafeLazy
import java.io.File
import logcat.LogPriority.ERROR
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
class AutofillSaveActivity : AppCompatActivity() {
@ -131,7 +132,7 @@ class AutofillSaveActivity : AppCompatActivity() {
val clientState =
intent?.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE)
?: run {
e { "AutofillDecryptActivity started without EXTRA_CLIENT_STATE" }
logcat(ERROR) { "AutofillDecryptActivity started without EXTRA_CLIENT_STATE" }
finish()
return@registerForActivityResult
}

View file

@ -17,9 +17,6 @@ import android.view.WindowManager
import androidx.annotation.CallSuper
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import com.github.ajalt.timberkt.Timber.tag
import com.github.ajalt.timberkt.e
import com.github.ajalt.timberkt.i
import com.github.michaelbull.result.getOr
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -29,6 +26,7 @@ import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.injection.prefs.SettingsPreferences
import dev.msfjarvis.aps.util.FeatureFlags
import dev.msfjarvis.aps.util.extensions.OPENPGP_PROVIDER
import dev.msfjarvis.aps.util.extensions.asLog
import dev.msfjarvis.aps.util.extensions.clipboard
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.snackbar
@ -37,6 +35,9 @@ import dev.msfjarvis.aps.util.services.ClipboardService
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import java.io.File
import javax.inject.Inject
import logcat.LogPriority.ERROR
import logcat.LogPriority.INFO
import logcat.logcat
import me.msfjarvis.openpgpktx.util.OpenPgpApi
import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
import org.openintents.openpgp.IOpenPgpService2
@ -82,7 +83,6 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
tag(TAG)
}
/**
@ -121,7 +121,7 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
* super.
*/
override fun onError(e: Exception) {
e(e) { "Callers must handle their own exceptions" }
logcat(ERROR) { e.asLog("Callers must handle their own exceptions") }
throw e
}
@ -176,7 +176,7 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
* @param result The intent returned by OpenKeychain
*/
fun getUserInteractionRequestIntent(result: Intent): IntentSender {
i { "RESULT_CODE_USER_INTERACTION_REQUIRED" }
logcat(INFO) { "RESULT_CODE_USER_INTERACTION_REQUIRED" }
return result.getParcelableExtra<PendingIntent>(OpenPgpApi.RESULT_INTENT)!!.intentSender
}
@ -196,8 +196,8 @@ open class BasePgpActivity : AppCompatActivity(), OpenPgpServiceConnection.OnBou
}
else -> {
snackbar(message = getString(R.string.openpgp_error_unknown, error.message))
e { "onError getErrorId: ${error.errorId}" }
e { "onError getMessage: ${error.message}" }
logcat(ERROR) { "onError getErrorId: ${error.errorId}" }
logcat(ERROR) { "onError getMessage: ${error.message}" }
}
}
}

View file

@ -12,7 +12,6 @@ import android.view.MenuItem
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 dagger.hilt.android.AndroidEntryPoint
@ -35,6 +34,9 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
import me.msfjarvis.openpgpktx.util.OpenPgpApi
import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
import org.openintents.openpgp.IOpenPgpService2
@ -110,7 +112,7 @@ class DecryptActivity : BasePgpActivity(), OpenPgpServiceConnection.OnBound {
}
override fun onError(e: Exception) {
e(e)
logcat(ERROR) { e.asLog() }
}
/**
@ -212,7 +214,7 @@ class DecryptActivity : BasePgpActivity(), OpenPgpServiceConnection.OnBound {
binding.recyclerView.adapter = adapter
adapter.updateItems(items)
}
.onFailure { e -> e(e) }
.onFailure { e -> logcat(ERROR) { e.asLog() } }
}
OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED -> {
val sender = getUserInteractionRequestIntent(result)

View file

@ -10,12 +10,14 @@ import android.os.Bundle
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 kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
import me.msfjarvis.openpgpktx.util.OpenPgpApi
import me.msfjarvis.openpgpktx.util.OpenPgpUtils
import org.openintents.openpgp.IOpenPgpService2
@ -43,7 +45,7 @@ class GetKeyIdsActivity : BasePgpActivity() {
}
override fun onError(e: Exception) {
e(e)
logcat(ERROR) { e.asLog() }
}
/** Get the Key ids from OpenKeychain */
@ -63,7 +65,7 @@ class GetKeyIdsActivity : BasePgpActivity() {
setResult(RESULT_OK, keyResult)
finish()
}
.onFailure { e -> e(e) }
.onFailure { e -> logcat(ERROR) { e.asLog() } }
}
OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED -> {
val sender = getUserInteractionRequestIntent(result)

View file

@ -20,7 +20,6 @@ import androidx.core.content.edit
import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.e
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.onSuccess
import com.github.michaelbull.result.runCatching
@ -39,6 +38,7 @@ import dev.msfjarvis.aps.ui.dialogs.XkPasswordGeneratorDialogFragment
import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.DirectoryStructure
import dev.msfjarvis.aps.util.crypto.GpgIdentifier
import dev.msfjarvis.aps.util.extensions.asLog
import dev.msfjarvis.aps.util.extensions.base64
import dev.msfjarvis.aps.util.extensions.commitChange
import dev.msfjarvis.aps.util.extensions.getString
@ -55,6 +55,9 @@ import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
import me.msfjarvis.openpgpktx.util.OpenPgpApi
import me.msfjarvis.openpgpktx.util.OpenPgpServiceConnection
@ -520,7 +523,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
}
.onFailure { e ->
if (e is IOException) {
e(e) { "Failed to write password file" }
logcat(ERROR) { e.asLog("Failed to write password file") }
setResult(RESULT_CANCELED)
MaterialAlertDialogBuilder(this@PasswordCreationActivity)
.setTitle(getString(R.string.password_creation_file_fail_title))
@ -529,7 +532,7 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
.setPositiveButton(android.R.string.ok) { _, _ -> finish() }
.show()
} else {
e(e)
logcat(ERROR) { e.asLog() }
}
}
}

View file

@ -18,7 +18,6 @@ import androidx.core.content.edit
import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.e
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.onSuccess
import com.github.michaelbull.result.runCatching
@ -35,6 +34,7 @@ import dev.msfjarvis.aps.ui.dialogs.PasswordGeneratorDialogFragment
import dev.msfjarvis.aps.ui.dialogs.XkPasswordGeneratorDialogFragment
import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.DirectoryStructure
import dev.msfjarvis.aps.util.extensions.asLog
import dev.msfjarvis.aps.util.extensions.base64
import dev.msfjarvis.aps.util.extensions.commitChange
import dev.msfjarvis.aps.util.extensions.getString
@ -49,6 +49,9 @@ import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
@AndroidEntryPoint
class PasswordCreationActivityV2 : BasePgpActivity() {
@ -393,7 +396,7 @@ class PasswordCreationActivityV2 : BasePgpActivity() {
}
.onFailure { e ->
if (e is IOException) {
e(e) { "Failed to write password file" }
logcat(ERROR) { e.asLog("Failed to write password file") }
setResult(RESULT_CANCELED)
MaterialAlertDialogBuilder(this@PasswordCreationActivityV2)
.setTitle(getString(R.string.password_creation_file_fail_title))
@ -402,7 +405,7 @@ class PasswordCreationActivityV2 : BasePgpActivity() {
.setPositiveButton(android.R.string.ok) { _, _ -> finish() }
.show()
} else {
e(e)
logcat(ERROR) { e.asLog() }
}
}
}

View file

@ -16,7 +16,6 @@ import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.Timber.tag
import com.github.michaelbull.result.fold
import com.github.michaelbull.result.getOr
import com.github.michaelbull.result.runCatching
@ -24,6 +23,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.databinding.FragmentXkpwgenBinding
import dev.msfjarvis.aps.ui.crypto.PasswordCreationActivity
import dev.msfjarvis.aps.util.extensions.asLog
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.pwgenxkpwd.CapsType
import dev.msfjarvis.aps.util.pwgenxkpwd.PasswordBuilder
@ -31,6 +31,8 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import logcat.LogPriority.ERROR
import logcat.logcat
import reactivecircus.flowbinding.android.widget.afterTextChanges
import reactivecircus.flowbinding.android.widget.selectionEvents
@ -119,7 +121,7 @@ class XkPasswordGeneratorDialogFragment : DialogFragment() {
success = { binding.xkPasswordText.text = it },
failure = { e ->
Toast.makeText(requireActivity(), e.message, Toast.LENGTH_SHORT).show()
tag("xkpw").e(e, "failure generating xkpasswd")
logcat("xkpw", ERROR) { e.asLog("failure generating xkpasswd") }
binding.xkPasswordText.text = FALLBACK_ERROR_PASS
},
)

View file

@ -7,7 +7,6 @@ package dev.msfjarvis.aps.ui.git.base
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import com.github.ajalt.timberkt.d
import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Result
import com.github.michaelbull.result.andThen
@ -30,6 +29,8 @@ import dev.msfjarvis.aps.util.settings.PreferenceKeys
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import logcat.asLog
import logcat.logcat
import net.schmizz.sshj.common.DisconnectReason
import net.schmizz.sshj.common.SSHException
import net.schmizz.sshj.transport.TransportException
@ -89,7 +90,7 @@ abstract class BaseGitActivity : ContinuationContainerActivity() {
if (!isExplicitlyUserInitiatedError(error)) {
gitPrefs.edit { remove(PreferenceKeys.HTTPS_PASSWORD) }
sharedPrefs.edit { remove(PreferenceKeys.SSH_OPENKEYSTORE_KEYID) }
d(error)
logcat { error.asLog() }
withContext(Dispatchers.Main) {
MaterialAlertDialogBuilder(this@BaseGitActivity).run {
setTitle(resources.getString(R.string.jgit_error_dialog_title))

View file

@ -12,7 +12,6 @@ import android.util.Patterns
import android.view.MenuItem
import androidx.core.os.postDelayed
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.e
import com.github.michaelbull.result.fold
import com.github.michaelbull.result.getOrElse
import com.github.michaelbull.result.onFailure
@ -26,6 +25,8 @@ import dev.msfjarvis.aps.ui.git.base.BaseGitActivity
import dev.msfjarvis.aps.ui.git.log.GitLogActivity
import dev.msfjarvis.aps.util.extensions.viewBinding
import kotlinx.coroutines.launch
import logcat.LogPriority.ERROR
import logcat.logcat
import org.eclipse.jgit.lib.Constants
import org.eclipse.jgit.lib.Repository
import org.eclipse.jgit.lib.RepositoryState
@ -88,7 +89,7 @@ class GitConfigActivity : BaseGitActivity() {
}
binding.gitLog.setOnClickListener {
runCatching { startActivity(Intent(this, GitLogActivity::class.java)) }.onFailure { ex ->
e(ex) { "Failed to start GitLogActivity" }
logcat(ERROR) { "Failed to start GitLogActivity\n${ex}" }
}
}
binding.gitAbortRebase.setOnClickListener {
@ -143,7 +144,7 @@ class GitConfigActivity : BaseGitActivity() {
}
}
.getOrElse { ex ->
e(ex) { "Error getting HEAD reference" }
logcat(ERROR) { "Error getting HEAD reference\n${ex}" }
getString(R.string.git_head_missing)
}
}

View file

@ -15,7 +15,6 @@ import androidx.core.os.postDelayed
import androidx.core.view.isVisible
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.e
import com.github.michaelbull.result.fold
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
@ -34,6 +33,9 @@ import dev.msfjarvis.aps.util.settings.Protocol
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
/**
* Activity that encompasses both the initial clone as well as editing the server config for future
@ -269,7 +271,7 @@ class GitServerConfigActivity : BaseGitActivity() {
}
}
.onFailure { e ->
e(e)
logcat(ERROR) { e.asLog() }
MaterialAlertDialogBuilder(this).setMessage(e.message).show()
}
lifecycleScope.launch {

View file

@ -8,12 +8,13 @@ package dev.msfjarvis.aps.ui.git.log
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.github.ajalt.timberkt.e
import dev.msfjarvis.aps.databinding.GitLogRowLayoutBinding
import dev.msfjarvis.aps.util.git.GitCommit
import dev.msfjarvis.aps.util.git.GitLogModel
import java.text.DateFormat
import java.util.Date
import logcat.LogPriority.ERROR
import logcat.logcat
private fun shortHash(hash: String): String {
return hash.substring(0 until 8)
@ -37,7 +38,7 @@ class GitLogAdapter : RecyclerView.Adapter<GitLogAdapter.ViewHolder>() {
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
val commit = model.get(position)
if (commit == null) {
e { "There is no git commit for view holder at position $position." }
logcat(ERROR) { "There is no git commit for view holder at position $position." }
return
}
viewHolder.bind(commit)

View file

@ -13,8 +13,6 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import androidx.fragment.app.Fragment
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.e
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -33,6 +31,9 @@ import dev.msfjarvis.aps.util.extensions.viewBinding
import dev.msfjarvis.aps.util.settings.PasswordSortOrder
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import java.io.File
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
@ -160,9 +161,9 @@ class RepoLocationFragment : Fragment(R.layout.fragment_repo_location) {
parentFragmentManager.performTransactionWithBackStack(KeySelectionFragment.newInstance())
}
.onFailure { e ->
e(e)
logcat(ERROR) { e.asLog() }
if (!localDir.delete()) {
d { "Failed to delete local repository: $localDir" }
logcat { "Failed to delete local repository: $localDir" }
}
finish()
}

View file

@ -25,9 +25,6 @@ import androidx.fragment.app.FragmentManager
import androidx.fragment.app.commit
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.e
import com.github.ajalt.timberkt.i
import com.github.michaelbull.result.fold
import com.github.michaelbull.result.onFailure
import com.github.michaelbull.result.runCatching
@ -68,6 +65,9 @@ import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.LogPriority.INFO
import logcat.logcat
const val PASSWORD_FRAGMENT_TAG = "PasswordsList"
@ -108,18 +108,18 @@ class PasswordStore : BaseGitActivity() {
val target = File(requireNotNull(intentData.getStringExtra("SELECTED_FOLDER_PATH")))
val repositoryPath = PasswordRepository.getRepositoryDirectory().absolutePath
if (!target.isDirectory) {
e { "Tried moving passwords to a non-existing folder." }
logcat(ERROR) { "Tried moving passwords to a non-existing folder." }
return@registerForActivityResult
}
d { "Moving passwords to ${intentData.getStringExtra("SELECTED_FOLDER_PATH")}" }
d { filesToMove.joinToString(", ") }
logcat { "Moving passwords to ${intentData.getStringExtra("SELECTED_FOLDER_PATH")}" }
logcat { filesToMove.joinToString(", ") }
lifecycleScope.launch(Dispatchers.IO) {
for (file in filesToMove) {
val source = File(file)
if (!source.exists()) {
e { "Tried moving something that appears non-existent." }
logcat(ERROR) { "Tried moving something that appears non-existent." }
continue
}
val destinationFile = File(target.absolutePath + "/" + source.name)
@ -127,7 +127,7 @@ class PasswordStore : BaseGitActivity() {
val sourceLongName = getLongName(requireNotNull(source.parent), repositoryPath, basename)
val destinationLongName = getLongName(target.absolutePath, repositoryPath, basename)
if (destinationFile.exists()) {
e { "Trying to move a file that already exists." }
logcat(ERROR) { "Trying to move a file that already exists." }
withContext(Dispatchers.Main) {
MaterialAlertDialogBuilder(this@PasswordStore)
.setTitle(resources.getString(R.string.password_exists_title))
@ -389,7 +389,7 @@ class PasswordStore : BaseGitActivity() {
private fun checkLocalRepository(localDir: File?) {
if (localDir != null && settings.getBoolean(PreferenceKeys.REPOSITORY_INITIALIZED, false)) {
d { "Check, dir: ${localDir.absolutePath}" }
logcat { "Check, dir: ${localDir.absolutePath}" }
// do not push the fragment if we already have it
if (getPasswordFragment() == null || settings.getBoolean(PreferenceKeys.REPO_CHANGED, false)
) {
@ -454,7 +454,7 @@ class PasswordStore : BaseGitActivity() {
fun createPassword() {
if (!validateState()) return
val currentDir = currentDir
i { "Adding file to : ${currentDir.absolutePath}" }
logcat(INFO) { "Adding file to : ${currentDir.absolutePath}" }
val intent = Intent(this, PasswordCreationActivity::class.java)
intent.putExtra("FILE_PATH", currentDir.absolutePath)
intent.putExtra("REPO_PATH", PasswordRepository.getRepositoryDirectory().absolutePath)
@ -632,7 +632,7 @@ class PasswordStore : BaseGitActivity() {
mapOf(source to destinationFile)
}
if (!source.renameTo(destinationFile)) {
e { "Something went wrong while moving $source to $destinationFile." }
logcat(ERROR) { "Something went wrong while moving $source to $destinationFile." }
withContext(Dispatchers.Main) {
MaterialAlertDialogBuilder(this@PasswordStore)
.setTitle(R.string.password_move_error_title)

View file

@ -12,11 +12,11 @@ import android.provider.DocumentsContract
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import com.github.ajalt.timberkt.d
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import logcat.logcat
class DirectorySelectionActivity : AppCompatActivity() {
@ -25,7 +25,7 @@ class DirectorySelectionActivity : AppCompatActivity() {
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri: Uri? ->
if (uri == null) return@registerForActivityResult
d { "Selected repository URI is $uri" }
logcat { "Selected repository URI is $uri" }
// TODO: This is fragile. Workaround until PasswordItem is backed by DocumentFile
val docId = DocumentsContract.getTreeDocumentId(uri)
val split = docId.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
@ -33,7 +33,7 @@ class DirectorySelectionActivity : AppCompatActivity() {
val repoPath = "${Environment.getExternalStorageDirectory()}/$path"
val prefs = sharedPrefs
d { "Selected repository path is $repoPath" }
logcat { "Selected repository path is $repoPath" }
if (Environment.getExternalStorageDirectory().path == repoPath) {
MaterialAlertDialogBuilder(this)

View file

@ -12,9 +12,8 @@ import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
import com.github.ajalt.timberkt.Timber.tag
import com.github.ajalt.timberkt.d
import dev.msfjarvis.aps.R
import logcat.logcat
object BiometricAuthenticator {
@ -43,7 +42,7 @@ object BiometricAuthenticator {
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
tag(TAG).d { "BiometricAuthentication error: errorCode=$errorCode, msg=$errString" }
logcat(TAG) { "BiometricAuthentication error: errorCode=$errorCode, msg=$errString" }
callback(
when (errorCode) {
BiometricPrompt.ERROR_CANCELED,

View file

@ -15,7 +15,6 @@ import android.service.autofill.SaveInfo
import android.view.inputmethod.InlineSuggestionsRequest
import android.widget.inline.InlinePresentationSpec
import androidx.annotation.RequiresApi
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.AutofillAction
import com.github.androidpasswordstore.autofillparser.FillableForm
import com.github.androidpasswordstore.autofillparser.fillWith
@ -28,6 +27,9 @@ import dev.msfjarvis.aps.ui.autofill.AutofillPublisherChangedActivity
import dev.msfjarvis.aps.ui.autofill.AutofillSaveActivity
import dev.msfjarvis.aps.util.FeatureFlags
import java.io.File
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
/** Implements [AutofillResponseBuilder]'s methods for API 30 and above */
@RequiresApi(Build.VERSION_CODES.R)
@ -213,7 +215,7 @@ class Api30AutofillResponseBuilder(form: FillableForm) {
callback.onSuccess(makeFillResponse(context, inlineSuggestionsRequest, matchedFiles))
},
failure = { e ->
e(e)
logcat(ERROR) { e.asLog() }
callback.onSuccess(makePublisherChangedResponse(context, inlineSuggestionsRequest, e))
}
)

View file

@ -8,9 +8,6 @@ import android.content.Context
import android.content.SharedPreferences
import android.widget.Toast
import androidx.core.content.edit
import com.github.ajalt.timberkt.Timber.e
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.w
import com.github.androidpasswordstore.autofillparser.FormOrigin
import com.github.androidpasswordstore.autofillparser.computeCertificatesHash
import com.github.michaelbull.result.Err
@ -18,6 +15,9 @@ import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import dev.msfjarvis.aps.R
import java.io.File
import logcat.LogPriority.ERROR
import logcat.LogPriority.WARN
import logcat.logcat
private const val PREFERENCES_AUTOFILL_APP_MATCHES = "oreo_autofill_app_matches"
private val Context.autofillAppMatches
@ -69,7 +69,7 @@ class AutofillMatcher {
context.autofillAppMatches.getString(tokenKey(formOrigin), null) ?: return false
val hashHasChanged = certificatesHash != storedCertificatesHash
if (hashHasChanged) {
e { "$packageName: stored=$storedCertificatesHash, new=$certificatesHash" }
logcat(ERROR) { "$packageName: stored=$storedCertificatesHash, new=$certificatesHash" }
true
} else {
false
@ -134,7 +134,7 @@ class AutofillMatcher {
if (hasFormOriginHashChanged(context, formOrigin)) {
// This should never happen since we already verified the publisher in
// getMatchesFor.
e { "App publisher changed between getMatchesFor and addMatchFor" }
logcat(ERROR) { "App publisher changed between getMatchesFor and addMatchFor" }
throw AutofillPublisherChangedException(formOrigin)
}
val matchPreferences = context.matchPreferences(formOrigin)
@ -154,7 +154,7 @@ class AutofillMatcher {
putStringSet(matchesKey(formOrigin), newFiles.map { it.absolutePath }.toSet())
}
storeFormOriginHash(context, formOrigin)
d { "Stored match for $formOrigin" }
logcat { "Stored match for $formOrigin" }
}
/**
@ -176,7 +176,7 @@ class AutofillMatcher {
// created with `putStringSet`.
@Suppress("UNCHECKED_CAST") val oldMatches = value as? Set<String>
if (oldMatches == null) {
w { "Failed to read matches for $key" }
logcat(WARN) { "Failed to read matches for $key" }
continue
}
// Delete all matches for file locations that are going to be overwritten, then
@ -188,7 +188,7 @@ class AutofillMatcher {
.minus(oldNewPathMap.values)
.map { match ->
val newPath = oldNewPathMap[match] ?: return@map match
d { "Updating match for $key: $match --> $newPath" }
logcat { "Updating match for $key: $match --> $newPath" }
newPath
}
.toSet()

View file

@ -13,7 +13,6 @@ import android.service.autofill.FillCallback
import android.service.autofill.FillResponse
import android.service.autofill.SaveInfo
import androidx.annotation.RequiresApi
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.AutofillAction
import com.github.androidpasswordstore.autofillparser.AutofillScenario
import com.github.androidpasswordstore.autofillparser.Credentials
@ -28,6 +27,9 @@ import dev.msfjarvis.aps.ui.autofill.AutofillPublisherChangedActivity
import dev.msfjarvis.aps.ui.autofill.AutofillSaveActivity
import dev.msfjarvis.aps.util.FeatureFlags
import java.io.File
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
class AutofillResponseBuilder(form: FillableForm) {
@ -180,7 +182,7 @@ class AutofillResponseBuilder(form: FillableForm) {
.fold(
success = { matchedFiles -> callback.onSuccess(makeFillResponse(context, matchedFiles)) },
failure = { e ->
e(e)
logcat(ERROR) { e.asLog() }
callback.onSuccess(makePublisherChangedResponse(context, e))
}
)
@ -209,7 +211,7 @@ class AutofillResponseBuilder(form: FillableForm) {
}
return builder.run {
if (scenario != null) fillWith(scenario, action, credentials)
else e { "Failed to recover scenario from client state" }
else logcat(ERROR) { "Failed to recover scenario from client state" }
build()
}
}

View file

@ -21,7 +21,6 @@ import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
import androidx.security.crypto.EncryptedSharedPreferences
import androidx.security.crypto.MasterKey
import com.github.ajalt.timberkt.d
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
import com.google.android.material.snackbar.Snackbar
@ -29,6 +28,7 @@ import dev.msfjarvis.aps.BuildConfig
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.util.git.operation.GitOperation
import logcat.logcat
/** Get an instance of [AutofillManager]. Only available on Android Oreo and above */
val Context.autofillManager: AutofillManager?
@ -91,7 +91,7 @@ suspend fun FragmentActivity.commitChange(
)
override fun preExecute(): Boolean {
d { "Committing with message: '$message'" }
logcat { "Committing with message: '$message'" }
return true
}
}

View file

@ -9,6 +9,7 @@ import com.github.michaelbull.result.runCatching
import dev.msfjarvis.aps.data.repo.PasswordRepository
import java.io.File
import java.util.Date
import logcat.asLog
import org.eclipse.jgit.lib.ObjectId
import org.eclipse.jgit.revwalk.RevCommit
@ -78,3 +79,6 @@ fun String.splitLines(): Array<String> {
/** Alias to [lazy] with thread safety mode always set to [LazyThreadSafetyMode.NONE]. */
fun <T> unsafeLazy(initializer: () -> T) = lazy(LazyThreadSafetyMode.NONE) { initializer.invoke() }
/** A convenience extension to turn a [Throwable] with a message into a loggable string. */
fun Throwable.asLog(message: String): String = "$message\n${asLog()}"

View file

@ -5,24 +5,28 @@
package dev.msfjarvis.aps.util.git
import com.github.ajalt.timberkt.e
import com.github.michaelbull.result.getOrElse
import com.github.michaelbull.result.runCatching
import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.util.extensions.asLog
import dev.msfjarvis.aps.util.extensions.hash
import dev.msfjarvis.aps.util.extensions.time
import dev.msfjarvis.aps.util.extensions.unsafeLazy
import logcat.LogPriority.ERROR
import logcat.logcat
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.revwalk.RevCommit
private val TAG = GitLogModel::class.java.simpleName
private fun commits(): Iterable<RevCommit> {
val repo = PasswordRepository.getRepository(null)
if (repo == null) {
e { "Could not access git repository" }
logcat(TAG, ERROR) { "Could not access git repository" }
return listOf()
}
return runCatching { Git(repo).log().call() }.getOrElse { e ->
e(e) { "Failed to obtain git commits" }
logcat(TAG, ERROR) { e.asLog("Failed to obtain git commits") }
listOf()
}
}
@ -48,7 +52,8 @@ class GitLogModel {
val size = cache.size
fun get(index: Int): GitCommit? {
if (index >= size) e { "Cannot get git commit with index $index. There are only $size." }
if (index >= size)
logcat(ERROR) { "Cannot get git commit with index $index. There are only $size." }
return cache.getOrNull(index)
}
}

View file

@ -7,7 +7,6 @@ package dev.msfjarvis.aps.util.git.operation
import android.content.Intent
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import com.github.ajalt.timberkt.e
import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok
import com.github.michaelbull.result.Result
@ -34,6 +33,9 @@ import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
import net.schmizz.sshj.common.DisconnectReason
import net.schmizz.sshj.common.SSHException
import net.schmizz.sshj.userauth.password.PasswordFinder
@ -110,7 +112,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
}
callingActivity.startActivity(intent)
}
.onFailure { e -> e(e) }
.onFailure { e -> logcat(ERROR) { e.asLog() } }
}
private fun registerAuthProviders(

View file

@ -9,7 +9,6 @@ import android.content.Intent
import androidx.activity.result.IntentSenderRequest
import androidx.core.content.edit
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.d
import dev.msfjarvis.aps.util.extensions.OPENPGP_PROVIDER
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.settings.PreferenceKeys
@ -21,6 +20,7 @@ import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.logcat
import net.schmizz.sshj.common.DisconnectReason
import net.schmizz.sshj.common.KeyType
import net.schmizz.sshj.userauth.UserAuthException
@ -81,7 +81,7 @@ class OpenKeychainKeyProvider private constructor(val activity: ContinuationCont
sshServiceConnection.connect(
object : SshAuthenticationConnection.OnBound {
override fun onBound(sshAgent: ISshAuthenticationService) {
d { "Bound to SshAuthenticationApi: $OPENPGP_PROVIDER" }
logcat { "Bound to SshAuthenticationApi: $OPENPGP_PROVIDER" }
cont.resume(SshAuthenticationApi(context, sshAgent))
}
@ -134,7 +134,7 @@ class OpenKeychainKeyProvider private constructor(val activity: ContinuationCont
request: Request,
resultOfUserInteraction: Intent? = null
): ApiResponse {
d { "executeRequest($request) called" }
logcat { "executeRequest($request) called" }
val result =
withContext(Dispatchers.Main) {
// If the request required user interaction, the data returned from the
@ -142,7 +142,7 @@ class OpenKeychainKeyProvider private constructor(val activity: ContinuationCont
// is used as the real request.
sshServiceApi.executeApi(resultOfUserInteraction ?: request.toIntent())!!
}
return parseResult(request, result).also { d { "executeRequest($request): $it" } }
return parseResult(request, result).also { logcat { "executeRequest($request): $it" } }
}
private suspend fun parseResult(request: Request, result: Intent): ApiResponse {

View file

@ -16,8 +16,6 @@ import android.util.Base64
import androidx.core.content.edit
import androidx.security.crypto.EncryptedFile
import androidx.security.crypto.MasterKey
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.e
import com.github.michaelbull.result.getOrElse
import com.github.michaelbull.result.runCatching
import dev.msfjarvis.aps.Application
@ -39,6 +37,8 @@ import javax.crypto.SecretKeyFactory
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import logcat.asLog
import logcat.logcat
import net.i2p.crypto.eddsa.EdDSAPrivateKey
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec
@ -101,7 +101,7 @@ object SshKey {
// It is fine to swallow the exception here since it will reappear when the key
// is
// used for SSH authentication and can then be shown in the UI.
d(error)
logcat { error.asLog() }
false
}
}
@ -317,13 +317,13 @@ object SshKey {
override fun getPublic(): PublicKey =
runCatching { androidKeystore.sshPublicKey!! }.getOrElse { error ->
e(error)
logcat { error.asLog() }
throw IOException("Failed to get public key '$KEYSTORE_ALIAS' from Android Keystore", error)
}
override fun getPrivate(): PrivateKey =
runCatching { androidKeystore.sshPrivateKey!! }.getOrElse { error ->
e(error)
logcat { error.asLog() }
throw IOException(
"Failed to access private key '$KEYSTORE_ALIAS' from Android Keystore",
error
@ -337,7 +337,7 @@ object SshKey {
override fun getPublic(): PublicKey =
runCatching { parseSshPublicKey(sshPublicKey!!)!! }.getOrElse { error ->
e(error)
logcat { error.asLog() }
throw IOException("Failed to get the public key for wrapped ed25519 key", error)
}
@ -353,7 +353,7 @@ object SshKey {
)
}
.getOrElse { error ->
e(error)
logcat { error.asLog() }
throw IOException("Failed to unwrap wrapped ed25519 key", error)
}

View file

@ -4,8 +4,6 @@
*/
package dev.msfjarvis.aps.util.git.sshj
import com.github.ajalt.timberkt.Timber
import com.github.ajalt.timberkt.d
import com.github.michaelbull.result.runCatching
import com.hierynomus.sshj.key.KeyAlgorithms
import com.hierynomus.sshj.transport.cipher.BlockCiphers
@ -14,6 +12,12 @@ import com.hierynomus.sshj.transport.kex.ExtInfoClientFactory
import com.hierynomus.sshj.transport.mac.Macs
import com.hierynomus.sshj.userauth.keyprovider.OpenSSHKeyV1KeyFile
import java.security.Security
import logcat.LogPriority.ERROR
import logcat.LogPriority.INFO
import logcat.LogPriority.VERBOSE
import logcat.LogPriority.WARN
import logcat.asLog
import logcat.logcat
import net.schmizz.keepalive.KeepAliveProvider
import net.schmizz.sshj.ConfigImpl
import net.schmizz.sshj.common.LoggerFactory
@ -49,7 +53,9 @@ fun setUpBouncyCastleForSshj() {
runCatching { Class.forName("sun.security.jca.Providers") }
Security.insertProviderAt(BouncyCastleProvider(), bcIndex + 1)
}
d { "JCE providers: ${Security.getProviders().joinToString { "${it.name} (${it.version})" }}" }
logcat("setUpBouncyCastleForSshj") {
"JCE providers: ${Security.getProviders().joinToString { "${it.name} (${it.version})" }}"
}
// Prevent sshj from forwarding all cryptographic operations to BC.
SecurityUtils.setRegisterBouncyCastle(false)
SecurityUtils.setSecurityProvider(null)
@ -147,10 +153,9 @@ private abstract class AbstractLogger(private val name: String) : Logger {
override fun error(marker: Marker?, msg: String, t: Throwable?) = error(msg, t)
}
object TimberLoggerFactory : LoggerFactory {
private class TimberLogger(name: String) : AbstractLogger(name) {
object LogcatLoggerFactory : LoggerFactory {
private class LogcatLogger(name: String) : AbstractLogger(name) {
// We defer the log level checks to Timber.
override fun isTraceEnabled() = true
override fun isDebugEnabled() = true
override fun isInfoEnabled() = true
@ -163,39 +168,39 @@ object TimberLoggerFactory : LoggerFactory {
private fun String.fix() = replace("""(?!<\\)\{\}""".toRegex(), "%s")
override fun t(message: String, t: Throwable?, vararg args: Any?) {
Timber.tag(name).v(t, message.fix(), *args)
logcat(name, VERBOSE) { message.fix().format(*args) + (t?.asLog() ?: "") }
}
override fun d(message: String, t: Throwable?, vararg args: Any?) {
Timber.tag(name).d(t, message.fix(), *args)
logcat(name) { message.fix().format(*args) + (t?.asLog() ?: "") }
}
override fun i(message: String, t: Throwable?, vararg args: Any?) {
Timber.tag(name).i(t, message.fix(), *args)
logcat(name, INFO) { message.fix().format(*args) + (t?.asLog() ?: "") }
}
override fun w(message: String, t: Throwable?, vararg args: Any?) {
Timber.tag(name).w(t, message.fix(), *args)
logcat(name, WARN) { message.fix().format(*args) + (t?.asLog() ?: "") }
}
override fun e(message: String, t: Throwable?, vararg args: Any?) {
Timber.tag(name).e(t, message.fix(), *args)
logcat(name, ERROR) { message.fix().format(*args) + (t?.asLog() ?: "") }
}
}
override fun getLogger(name: String): Logger {
return TimberLogger(name)
return LogcatLogger(name)
}
override fun getLogger(clazz: Class<*>): Logger {
return TimberLogger(clazz.name)
return LogcatLogger(clazz.name)
}
}
class SshjConfig : ConfigImpl() {
init {
loggerFactory = TimberLoggerFactory
loggerFactory = LogcatLoggerFactory
keepAliveProvider = KeepAliveProvider.HEARTBEAT
version = "OpenSSH_8.2p1 Ubuntu-4ubuntu0.1"

View file

@ -5,8 +5,6 @@
package dev.msfjarvis.aps.util.git.sshj
import android.util.Base64
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.w
import com.github.michaelbull.result.getOrElse
import com.github.michaelbull.result.runCatching
import dev.msfjarvis.aps.util.git.operation.CredentialFinder
@ -20,6 +18,8 @@ import kotlin.coroutines.Continuation
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import logcat.LogPriority.WARN
import logcat.logcat
import net.schmizz.sshj.SSHClient
import net.schmizz.sshj.common.Buffer.PlainBuffer
import net.schmizz.sshj.common.DisconnectReason
@ -76,7 +76,7 @@ class SshjSessionFactory(private val authMethod: SshAuthMethod, private val host
): RemoteSession {
return currentSession
?: SshjSession(uri, uri.user, authMethod, hostKeyFile).connect().also {
d { "New SSH connection created" }
logcat { "New SSH connection created" }
currentSession = it
}
}
@ -96,13 +96,15 @@ private fun makeTofuHostKeyVerifier(hostKeyFile: File): HostKeyVerifier {
digest.update(PlainBuffer().putPublicKey(key).compactData)
val digestData = digest.digest()
val hostKeyEntry = "SHA256:${Base64.encodeToString(digestData, Base64.NO_WRAP)}"
d { "Trusting host key on first use: $hostKeyEntry" }
logcat(SshjSessionFactory::class.java.simpleName) {
"Trusting host key on first use: $hostKeyEntry"
}
hostKeyFile.writeText(hostKeyEntry)
true
}
} else {
val hostKeyEntry = hostKeyFile.readText()
d { "Pinned host key: $hostKeyEntry" }
logcat(SshjSessionFactory::class.java.simpleName) { "Pinned host key: $hostKeyEntry" }
return FingerprintVerifier.getInstance(hostKeyEntry)
}
}
@ -122,12 +124,12 @@ private class SshjSession(
// URIish's String constructor cannot handle '@' in the user part of the URI and the URL
// constructor can't be used since Java's URL does not recognize the ssh scheme. We thus
// need to patch everything up ourselves.
d { "Before fixup: user=${uri.user}, host=${uri.host}" }
logcat { "Before fixup: user=${uri.user}, host=${uri.host}" }
val userPlusHost = "${uri.user}@${uri.host}"
val realUser = userPlusHost.substringBeforeLast('@')
val realHost = userPlusHost.substringAfterLast('@')
uri.setUser(realUser).setHost(realHost).also {
d { "After fixup: user=${it.user}, host=${it.host}" }
logcat { "After fixup: user=${it.user}, host=${it.host}" }
}
} else {
uri
@ -162,7 +164,7 @@ private class SshjSession(
override fun exec(commandName: String?, timeout: Int): Process {
if (currentCommand != null) {
w { "Killing old command" }
logcat(WARN) { "Killing old command" }
disconnect()
}
val session = ssh.startSession()

View file

@ -16,7 +16,6 @@ import android.os.IBinder
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.content.getSystemService
import com.github.ajalt.timberkt.d
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.extensions.clipboard
import dev.msfjarvis.aps.util.extensions.sharedPrefs
@ -29,6 +28,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.logcat
class ClipboardService : Service() {
@ -82,7 +82,7 @@ class ClipboardService : Service() {
if (clipboard != null) {
scope.launch {
d { "Clearing the clipboard" }
logcat { "Clearing the clipboard" }
val clip = ClipData.newPlainText("pgp_handler_result_pm", "")
clipboard.setPrimaryClip(clip)
if (deepClear) {
@ -95,7 +95,7 @@ class ClipboardService : Service() {
}
}
} else {
d { "Cannot get clipboard manager service" }
logcat { "Cannot get clipboard manager service" }
}
}
@ -169,7 +169,7 @@ class ClipboardService : Service() {
if (manager != null) {
manager.createNotificationChannel(serviceChannel)
} else {
d { "Failed to create notification channel" }
logcat { "Failed to create notification channel" }
}
}
}

View file

@ -14,8 +14,6 @@ import android.service.autofill.FillResponse
import android.service.autofill.SaveCallback
import android.service.autofill.SaveRequest
import androidx.annotation.RequiresApi
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.e
import com.github.androidpasswordstore.autofillparser.AutofillScenario
import com.github.androidpasswordstore.autofillparser.Credentials
import com.github.androidpasswordstore.autofillparser.FillableForm
@ -34,6 +32,8 @@ import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.hasFlag
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import logcat.LogPriority.ERROR
import logcat.logcat
@RequiresApi(Build.VERSION_CODES.O)
class OreoAutofillService : AutofillService() {
@ -92,7 +92,7 @@ class OreoAutofillService : AutofillService() {
getCustomSuffixes(),
)
?: run {
d { "Form cannot be filled" }
logcat { "Form cannot be filled" }
callback.onSuccess(null)
return
}
@ -117,21 +117,21 @@ class OreoAutofillService : AutofillService() {
val clientState =
request.clientState
?: run {
e { "Received save request without client state" }
logcat(ERROR) { "Received save request without client state" }
callback.onFailure(getString(R.string.oreo_autofill_save_internal_error))
return
}
val scenario =
AutofillScenario.fromClientState(clientState)?.recoverNodes(structure)
?: run {
e { "Failed to recover client state or nodes from client state" }
logcat(ERROR) { "Failed to recover client state or nodes from client state" }
callback.onFailure(getString(R.string.oreo_autofill_save_internal_error))
return
}
val formOrigin =
FormOrigin.fromBundle(clientState)
?: run {
e { "Failed to recover form origin from client state" }
logcat(ERROR) { "Failed to recover form origin from client state" }
callback.onFailure(getString(R.string.oreo_autofill_save_internal_error))
return
}

View file

@ -15,13 +15,13 @@ import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.content.getSystemService
import androidx.documentfile.provider.DocumentFile
import com.github.ajalt.timberkt.d
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.data.repo.PasswordRepository
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.Calendar
import java.util.TimeZone
import logcat.logcat
class PasswordExportService : Service() {
@ -62,7 +62,7 @@ class PasswordExportService : Service() {
val repositoryDirectory = requireNotNull(PasswordRepository.getRepositoryDirectory())
val sourcePassDir = DocumentFile.fromFile(repositoryDirectory)
d { "Copying ${repositoryDirectory.path} to $targetDirectory" }
logcat { "Copying ${repositoryDirectory.path} to $targetDirectory" }
val dateString =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -146,7 +146,7 @@ class PasswordExportService : Service() {
if (manager != null) {
manager.createNotificationChannel(serviceChannel)
} else {
d { "Failed to create notification channel" }
logcat { "Failed to create notification channel" }
}
}
}

View file

@ -8,14 +8,17 @@ package dev.msfjarvis.aps.util.settings
import android.content.SharedPreferences
import androidx.core.content.edit
import com.github.ajalt.timberkt.e
import com.github.ajalt.timberkt.i
import com.github.michaelbull.result.get
import com.github.michaelbull.result.runCatching
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.git.sshj.SshKey
import java.io.File
import java.net.URI
import logcat.LogPriority.ERROR
import logcat.LogPriority.INFO
import logcat.logcat
private const val TAG = "Migrations"
fun runMigrations(filesDirPath: String, sharedPrefs: SharedPreferences, gitSettings: GitSettings) {
migrateToGitUrlBasedConfig(sharedPrefs, gitSettings)
@ -26,7 +29,7 @@ fun runMigrations(filesDirPath: String, sharedPrefs: SharedPreferences, gitSetti
private fun migrateToGitUrlBasedConfig(sharedPrefs: SharedPreferences, gitSettings: GitSettings) {
val serverHostname = sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_SERVER) ?: return
i { "Migrating to URL-based Git config" }
logcat(TAG, INFO) { "Migrating to URL-based Git config" }
val serverPort = sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_PORT) ?: ""
val serverUser = sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_USERNAME) ?: ""
val serverPath = sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_LOCATION) ?: ""
@ -79,7 +82,7 @@ private fun migrateToGitUrlBasedConfig(sharedPrefs: SharedPreferences, gitSettin
newBranch = gitSettings.branch
) != GitSettings.UpdateConnectionSettingsResult.Valid
) {
e { "Failed to migrate to URL-based Git config, generated URL is invalid" }
logcat(TAG, ERROR) { "Failed to migrate to URL-based Git config, generated URL is invalid" }
}
}

View file

@ -13,12 +13,12 @@ import android.graphics.drawable.Icon
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService
import com.github.ajalt.timberkt.d
import dagger.Reusable
import dagger.hilt.android.qualifiers.ApplicationContext
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.data.password.PasswordItem
import javax.inject.Inject
import logcat.logcat
@Reusable
class ShortcutHandler
@ -70,7 +70,7 @@ constructor(
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
val shortcutManager: ShortcutManager = context.getSystemService() ?: return
if (!shortcutManager.isRequestPinShortcutSupported) {
d { "addPinnedShortcut: pin shortcuts unsupported" }
logcat { "addPinnedShortcut: pin shortcuts unsupported" }
return
}
val shortcut = buildShortcut(item, intent)

View file

@ -17,8 +17,6 @@ import android.view.autofill.AutofillManager
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.github.ajalt.timberkt.e
import com.github.ajalt.timberkt.w
import com.github.androidpasswordstore.autofillparser.AutofillAction
import com.github.androidpasswordstore.autofillparser.Credentials
import com.github.michaelbull.result.onFailure
@ -39,6 +37,8 @@ import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import logcat.LogPriority.WARN
import logcat.logcat
suspend fun <T> Task<T>.suspendableAwait() =
suspendCoroutine<T> { cont ->
@ -62,14 +62,14 @@ class AutofillSmsActivity : AppCompatActivity() {
val googleApiAvailabilityInstance = GoogleApiAvailability.getInstance()
val googleApiStatus = googleApiAvailabilityInstance.isGooglePlayServicesAvailable(context)
if (googleApiStatus != ConnectionResult.SUCCESS) {
w {
logcat(WARN) {
"Google Play Services unavailable or not updated: ${googleApiAvailabilityInstance.getErrorString(googleApiStatus)}"
}
return false
}
// https://developer.android.com/guide/topics/text/autofill-services#sms-autofill
if (googleApiAvailabilityInstance.getApkVersion(context) < 190056000) {
w { "Google Play Service 19.0.56 or higher required for SMS OTP Autofill" }
logcat(WARN) { "Google Play Service 19.0.56 or higher required for SMS OTP Autofill" }
return false
}
return true
@ -103,7 +103,7 @@ class AutofillSmsActivity : AppCompatActivity() {
clientState =
intent?.getBundleExtra(AutofillManager.EXTRA_CLIENT_STATE)
?: run {
e { "AutofillSmsActivity started without EXTRA_CLIENT_STATE" }
logcat(WARN) { "AutofillSmsActivity started without EXTRA_CLIENT_STATE" }
finish()
return
}

View file

@ -21,6 +21,6 @@ dependencies {
implementation(libs.androidx.autofill)
implementation(libs.kotlin.coroutines.android)
implementation(libs.kotlin.coroutines.core)
implementation(libs.thirdparty.timberkt)
implementation(libs.thirdparty.logcat)
testImplementation(libs.bundles.testDependencies)
}

View file

@ -12,7 +12,7 @@ import android.os.Build
import android.os.Bundle
import android.view.autofill.AutofillId
import androidx.annotation.RequiresApi
import com.github.ajalt.timberkt.d
import logcat.logcat
/**
* A unique identifier for either an Android app (package name) or a website (origin minus port).
@ -84,7 +84,7 @@ private class AutofillFormParser(
private val webOrigins = mutableSetOf<String>()
init {
d { "Request from $appPackage (${computeCertificatesHash(context, appPackage)})" }
logcat { "Request from $appPackage (${computeCertificatesHash(context, appPackage)})" }
parseStructure(structure)
}
@ -92,7 +92,7 @@ private class AutofillFormParser(
val formOrigin = determineFormOrigin(context)
init {
d { "Origin: $formOrigin" }
logcat { "Origin: $formOrigin" }
}
private fun parseStructure(structure: AssistStructure) {
@ -111,11 +111,11 @@ private class AutofillFormParser(
FormField(node, fieldIndex, false)
}
if (field.relevantField) {
d { "Relevant: $field" }
logcat { "Relevant: $field" }
relevantFields.add(field)
fieldIndex++
} else {
d { "Ignored : $field" }
logcat { "Ignored : $field" }
ignoredIds.add(field.autofillId)
}
for (i in 0 until node.childCount) {
@ -134,7 +134,7 @@ private class AutofillFormParser(
if (trustedBrowserInfo == null) return
node.webOrigin?.let {
if (it !in webOrigins) {
d { "Origin encountered: $it" }
logcat { "Origin encountered: $it" }
webOrigins.add(it)
}
}

View file

@ -15,9 +15,9 @@ import android.util.Base64
import android.view.autofill.AutofillId
import android.widget.Toast
import androidx.annotation.RequiresApi
import com.github.ajalt.timberkt.Timber.tag
import com.github.ajalt.timberkt.e
import java.security.MessageDigest
import logcat.LogPriority.ERROR
import logcat.logcat
private fun ByteArray.sha256(): ByteArray {
return MessageDigest.getInstance("SHA-256").run {
@ -59,7 +59,7 @@ public fun computeCertificatesHash(context: Context, appPackage: String): String
info.signingInfo.signingCertificateHistory ?: info.signingInfo.apkContentsSigners
val stableHashNew = stableHash(signaturesNew.map { it.toByteArray() })
if (stableHashNew != stableHashOld)
tag("CertificatesHash").e {
logcat("CertificatesHash", ERROR) {
"Mismatch between old and new hash: $stableHashNew != $stableHashOld"
}
}

View file

@ -11,7 +11,9 @@ import android.service.autofill.Dataset
import android.view.autofill.AutofillId
import android.view.autofill.AutofillValue
import androidx.annotation.RequiresApi
import com.github.ajalt.timberkt.e
import logcat.LogPriority.ERROR
import logcat.asLog
import logcat.logcat
public enum class AutofillAction {
Match,
@ -68,7 +70,7 @@ public sealed class AutofillScenario<out T : Any> {
}
.build()
} catch (e: Throwable) {
e(e)
logcat(ERROR) { e.asLog() }
null
}
}

View file

@ -6,8 +6,8 @@ package com.github.androidpasswordstore.autofillparser
import android.os.Build
import androidx.annotation.RequiresApi
import com.github.ajalt.timberkt.d
import com.github.ajalt.timberkt.w
import logcat.LogPriority.WARN
import logcat.logcat
@DslMarker internal annotation class AutofillDsl
@ -116,16 +116,16 @@ internal class SingleFieldMatcher(
val new = current.filter { tieBreaker(it, alreadyMatched) }
// skipping those tie breakers that are not satisfied for any remaining field...
if (new.isEmpty()) {
d { "Tie breaker #${i + 1}: Didn't match any field; skipping" }
logcat { "Tie breaker #${i + 1}: Didn't match any field; skipping" }
continue
}
// and return if the available options have been narrowed to a single field.
if (new.size == 1) {
d { "Tie breaker #${i + 1}: Success" }
logcat { "Tie breaker #${i + 1}: Success" }
current = new
break
}
d { "Tie breaker #${i + 1}: Matched ${new.size} fields; continuing" }
logcat { "Tie breaker #${i + 1}: Matched ${new.size} fields; continuing" }
current = new
}
listOf(current.singleOrNull() ?: return null)
@ -154,16 +154,16 @@ private class PairOfFieldsMatcher(
for ((i, tieBreaker) in tieBreakers.withIndex()) {
val new = current.filter { tieBreaker(it, alreadyMatched) }
if (new.isEmpty()) {
d { "Tie breaker #${i + 1}: Didn't match any pair of fields; skipping" }
logcat { "Tie breaker #${i + 1}: Didn't match any pair of fields; skipping" }
continue
}
// and return if the available options have been narrowed to a single field.
if (new.size == 1) {
d { "Tie breaker #${i + 1}: Success" }
logcat { "Tie breaker #${i + 1}: Success" }
current = new
break
}
d { "Tie breaker #${i + 1}: Matched ${new.size} pairs of fields; continuing" }
logcat { "Tie breaker #${i + 1}: Matched ${new.size} pairs of fields; continuing" }
current = new
}
current.singleOrNull()?.toList()
@ -323,14 +323,14 @@ private constructor(
isManualRequest: Boolean
): AutofillScenario<FormField>? {
if (singleOriginMode && !applyInSingleOriginMode) {
d { "$name: Skipped in single origin mode" }
logcat { "$name: Skipped in single origin mode" }
return null
}
if (!isManualRequest && applyOnManualRequestOnly) {
d { "$name: Skipped since not a manual request" }
logcat { "$name: Skipped since not a manual request" }
return null
}
d { "$name: Applying..." }
logcat { "$name: Applying..." }
val scenarioBuilder = AutofillScenario.Builder<FormField>()
val alreadyMatched = mutableListOf<FormField>()
for ((type, matcher, optional, matchHidden) in matchers) {
@ -343,13 +343,13 @@ private constructor(
val matchResult =
matcher.match(fieldsToMatchOn, alreadyMatched)
?: if (optional) {
d { "$name: Skipping optional $type matcher" }
logcat { "$name: Skipping optional $type matcher" }
continue
} else {
d { "$name: Required $type matcher didn't match; passing to next rule" }
logcat { "$name: Required $type matcher didn't match; passing to next rule" }
return null
}
d { "$name: Matched $type" }
logcat { "$name: Matched $type" }
when (type) {
FillableFieldType.Username -> {
check(matchResult.size == 1 && scenarioBuilder.username == null)
@ -370,9 +370,9 @@ private constructor(
return scenarioBuilder.build().takeIf { scenario ->
scenario.passesOriginCheck(singleOriginMode = singleOriginMode).also { passed ->
if (passed) {
d { "$name: Detected scenario:\n$scenario" }
logcat { "$name: Detected scenario:\n$scenario" }
} else {
w { "$name: Scenario failed origin check:\n$scenario" }
logcat(WARN) { "$name: Scenario failed origin check:\n$scenario" }
}
}
}
@ -411,13 +411,13 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
isManualRequest: Boolean
): AutofillScenario<FormField>? {
val possiblePasswordFields = fields.filter { it.passwordCertainty >= CertaintyLevel.Possible }
d { "Possible password fields: ${possiblePasswordFields.size}" }
logcat { "Possible password fields: ${possiblePasswordFields.size}" }
val possibleUsernameFields = fields.filter { it.usernameCertainty >= CertaintyLevel.Possible }
d { "Possible username fields: ${possibleUsernameFields.size}" }
logcat { "Possible username fields: ${possibleUsernameFields.size}" }
val possibleOtpFields = fields.filter { it.otpCertainty >= CertaintyLevel.Possible }
d { "Possible otp fields: ${possibleOtpFields.size}" }
logcat { "Possible otp fields: ${possibleOtpFields.size}" }
// Return the result of the first rule that matches
d { "Rules: ${rules.size}" }
logcat { "Rules: ${rules.size}" }
for (rule in rules) {
return rule.match(
possiblePasswordFields,

View file

@ -74,12 +74,11 @@ thirdparty-flowbinding-android = { module = "io.github.reactivecircus.flowbindin
thirdparty-jgit = "org.eclipse.jgit:org.eclipse.jgit:3.7.1.201504261725-r"
thirdparty-kotlinResult = "com.michael-bull.kotlin-result:kotlin-result:1.1.12"
thirdparty-leakcanary = "com.squareup.leakcanary:leakcanary-android:2.7"
thirdparty-logcat = "com.squareup.logcat:logcat:0.1"
thirdparty-modernAndroidPrefs = "de.maxr1998:modernandroidpreferences:2.1.0"
thirdparty-plumber = "com.squareup.leakcanary:plumber-android:2.7"
thirdparty-sshj = "com.hierynomus:sshj:0.31.0"
thirdparty-sshauth = "com.github.open-keychain.open-keychain:sshauthentication-api:5.7.5"
thirdparty-timber = "com.jakewharton.timber:timber:5.0.1"
thirdparty-timberkt = "com.github.ajalt:timberkt:1.5.1"
thirdparty-whatthestack = "com.github.haroldadmin:WhatTheStack:0.3.1"
thirdparty-nonfree-googlePlayAuthApiPhone = "com.google.android.gms:play-services-auth-api-phone:17.5.1"