diff options
| author | Harsh Shandilya <me@msfjarvis.dev> | 2021-05-15 12:56:49 +0530 |
|---|---|---|
| committer | Harsh Shandilya <me@msfjarvis.dev> | 2021-05-15 15:40:20 +0530 |
| commit | 7e2eb2425e7b9b6ccb37b7b89f19de3fa7a20c44 (patch) | |
| tree | 6b8a9557ac51b5fab5d2ad7611084cf0de6c57cf /app/src/main/java/dev/msfjarvis/aps/util | |
| parent | 2fcb285e276594842798be6990b92ba09e733f49 (diff) | |
| download | HardenedPass-7e2eb2425e7b9b6ccb37b7b89f19de3fa7a20c44.tar.gz HardenedPass-7e2eb2425e7b9b6ccb37b7b89f19de3fa7a20c44.zip | |
all: reformat with Spotless again
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
Diffstat (limited to 'app/src/main/java/dev/msfjarvis/aps/util')
37 files changed, 418 insertions, 154 deletions
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/auth/BiometricAuthenticator.kt b/app/src/main/java/dev/msfjarvis/aps/util/auth/BiometricAuthenticator.kt index c3655298..7236ac7c 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/auth/BiometricAuthenticator.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/auth/BiometricAuthenticator.kt @@ -19,7 +19,8 @@ import dev.msfjarvis.aps.R object BiometricAuthenticator { private const val TAG = "BiometricAuthenticator" - private const val validAuthenticators = Authenticators.DEVICE_CREDENTIAL or Authenticators.BIOMETRIC_WEAK + private const val validAuthenticators = + Authenticators.DEVICE_CREDENTIAL or Authenticators.BIOMETRIC_WEAK sealed class Result { data class Success(val cryptoObject: BiometricPrompt.CryptoObject?) : Result() @@ -29,7 +30,8 @@ object BiometricAuthenticator { } fun canAuthenticate(activity: FragmentActivity): Boolean { - return BiometricManager.from(activity).canAuthenticate(validAuthenticators) == BiometricManager.BIOMETRIC_SUCCESS + return BiometricManager.from(activity).canAuthenticate(validAuthenticators) == + BiometricManager.BIOMETRIC_SUCCESS } fun authenticate( @@ -55,7 +57,11 @@ object BiometricAuthenticator { BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> { Result.HardwareUnavailableOrDisabled } - else -> Result.Failure(errorCode, activity.getString(R.string.biometric_auth_error_reason, errString)) + else -> + Result.Failure( + errorCode, + activity.getString(R.string.biometric_auth_error_reason, errString) + ) } ) } @@ -77,7 +83,11 @@ object BiometricAuthenticator { .setTitle(activity.getString(dialogTitleRes)) .setAllowedAuthenticators(validAuthenticators) .build() - BiometricPrompt(activity, ContextCompat.getMainExecutor(activity.applicationContext), authCallback) + BiometricPrompt( + activity, + ContextCompat.getMainExecutor(activity.applicationContext), + authCallback + ) .authenticate(promptInfo) } else { callback(Result.HardwareUnavailableOrDisabled) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/autofill/Api30AutofillResponseBuilder.kt b/app/src/main/java/dev/msfjarvis/aps/util/autofill/Api30AutofillResponseBuilder.kt index a39db31d..ea03bb23 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/autofill/Api30AutofillResponseBuilder.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/autofill/Api30AutofillResponseBuilder.kt @@ -61,7 +61,11 @@ class Api30AutofillResponseBuilder(form: FillableForm) { } } - private fun makeMatchDataset(context: Context, file: File, imeSpec: InlinePresentationSpec?): Dataset? { + private fun makeMatchDataset( + context: Context, + file: File, + imeSpec: InlinePresentationSpec? + ): Dataset? { if (!scenario.hasFieldsToFillOn(AutofillAction.Match)) return null val metadata = makeFillMatchMetadata(context, file) val intentSender = AutofillDecryptActivity.makeDecryptFileIntentSender(file, context) @@ -82,12 +86,21 @@ class Api30AutofillResponseBuilder(form: FillableForm) { return makeIntentDataset(context, AutofillAction.Generate, intentSender, metadata, imeSpec) } - private fun makeFillOtpFromSmsDataset(context: Context, imeSpec: InlinePresentationSpec?): Dataset? { + private fun makeFillOtpFromSmsDataset( + context: Context, + imeSpec: InlinePresentationSpec? + ): Dataset? { if (!scenario.hasFieldsToFillOn(AutofillAction.FillOtpFromSms)) return null if (!AutofillSmsActivity.shouldOfferFillFromSms(context)) return null val metadata = makeFillOtpFromSmsMetadata(context) val intentSender = AutofillSmsActivity.makeFillOtpFromSmsIntentSender(context) - return makeIntentDataset(context, AutofillAction.FillOtpFromSms, intentSender, metadata, imeSpec) + return makeIntentDataset( + context, + AutofillAction.FillOtpFromSms, + intentSender, + metadata, + imeSpec + ) } private fun makePublisherChangedDataset( @@ -150,7 +163,12 @@ class Api30AutofillResponseBuilder(form: FillableForm) { addDataset(it) } if (datasetCount == 0) return null - setHeader(makeRemoteView(context, makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)))) + setHeader( + makeRemoteView( + context, + makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)) + ) + ) makeSaveInfo()?.let { setSaveInfo(it) } setClientState(clientState) setIgnoredIds(*ignoredIds.toTypedArray()) @@ -177,7 +195,11 @@ class Api30AutofillResponseBuilder(form: FillableForm) { } /** Creates and returns a suitable [FillResponse] to the Autofill framework. */ - fun fillCredentials(context: Context, inlineSuggestionsRequest: InlineSuggestionsRequest?, callback: FillCallback) { + fun fillCredentials( + context: Context, + inlineSuggestionsRequest: InlineSuggestionsRequest?, + callback: FillCallback + ) { AutofillMatcher.getMatchesFor(context, formOrigin) .fold( success = { matchedFiles -> diff --git a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillMatcher.kt b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillMatcher.kt index 418843f6..ea10c1ac 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillMatcher.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillMatcher.kt @@ -35,7 +35,9 @@ private fun Context.matchPreferences(formOrigin: FormOrigin): SharedPreferences } class AutofillPublisherChangedException(val formOrigin: FormOrigin) : - Exception("The publisher of '${formOrigin.identifier}' changed since an entry was first matched with this app") { + Exception( + "The publisher of '${formOrigin.identifier}' changed since an entry was first matched with this app" + ) { init { require(formOrigin is FormOrigin.App) @@ -50,10 +52,12 @@ class AutofillMatcher { private const val MAX_NUM_MATCHES = 10 private const val PREFERENCE_PREFIX_TOKEN = "token;" - private fun tokenKey(formOrigin: FormOrigin.App) = "$PREFERENCE_PREFIX_TOKEN${formOrigin.identifier}" + private fun tokenKey(formOrigin: FormOrigin.App) = + "$PREFERENCE_PREFIX_TOKEN${formOrigin.identifier}" private const val PREFERENCE_PREFIX_MATCHES = "matches;" - private fun matchesKey(formOrigin: FormOrigin) = "$PREFERENCE_PREFIX_MATCHES${formOrigin.identifier}" + private fun matchesKey(formOrigin: FormOrigin) = + "$PREFERENCE_PREFIX_MATCHES${formOrigin.identifier}" private fun hasFormOriginHashChanged(context: Context, formOrigin: FormOrigin): Boolean { return when (formOrigin) { @@ -61,7 +65,8 @@ class AutofillMatcher { is FormOrigin.App -> { val packageName = formOrigin.identifier val certificatesHash = computeCertificatesHash(context, packageName) - val storedCertificatesHash = context.autofillAppMatches.getString(tokenKey(formOrigin), null) ?: return false + val storedCertificatesHash = + context.autofillAppMatches.getString(tokenKey(formOrigin), null) ?: return false val hashHasChanged = certificatesHash != storedCertificatesHash if (hashHasChanged) { e { "$packageName: stored=$storedCertificatesHash, new=$certificatesHash" } @@ -91,15 +96,21 @@ class AutofillMatcher { * time the user associated an entry with it, an [AutofillPublisherChangedException] will be * thrown. */ - fun getMatchesFor(context: Context, formOrigin: FormOrigin): Result<List<File>, AutofillPublisherChangedException> { + fun getMatchesFor( + context: Context, + formOrigin: FormOrigin + ): Result<List<File>, AutofillPublisherChangedException> { if (hasFormOriginHashChanged(context, formOrigin)) { return Err(AutofillPublisherChangedException(formOrigin)) } val matchPreferences = context.matchPreferences(formOrigin) - val matchedFiles = matchPreferences.getStringSet(matchesKey(formOrigin), emptySet())!!.map { File(it) } + val matchedFiles = + matchPreferences.getStringSet(matchesKey(formOrigin), emptySet())!!.map { File(it) } return Ok( matchedFiles.filter { it.exists() }.also { validFiles -> - matchPreferences.edit { putStringSet(matchesKey(formOrigin), validFiles.map { it.absolutePath }.toSet()) } + matchPreferences.edit { + putStringSet(matchesKey(formOrigin), validFiles.map { it.absolutePath }.toSet()) + } } ) } @@ -127,7 +138,8 @@ class AutofillMatcher { throw AutofillPublisherChangedException(formOrigin) } val matchPreferences = context.matchPreferences(formOrigin) - val matchedFiles = matchPreferences.getStringSet(matchesKey(formOrigin), emptySet())!!.map { File(it) } + val matchedFiles = + matchPreferences.getStringSet(matchesKey(formOrigin), emptySet())!!.map { File(it) } val newFiles = setOf(file.absoluteFile).union(matchedFiles) if (newFiles.size > MAX_NUM_MATCHES) { Toast.makeText( @@ -138,7 +150,9 @@ class AutofillMatcher { .show() return } - matchPreferences.edit { putStringSet(matchesKey(formOrigin), newFiles.map { it.absolutePath }.toSet()) } + matchPreferences.edit { + putStringSet(matchesKey(formOrigin), newFiles.map { it.absolutePath }.toSet()) + } storeFormOriginHash(context, formOrigin) d { "Stored match for $formOrigin" } } @@ -153,7 +167,8 @@ class AutofillMatcher { delete: Collection<File> = emptyList() ) { val deletePathList = delete.map { it.absolutePath } - val oldNewPathMap = moveFromTo.mapValues { it.value.absolutePath }.mapKeys { it.key.absolutePath } + val oldNewPathMap = + moveFromTo.mapValues { it.value.absolutePath }.mapKeys { it.key.absolutePath } for (prefs in listOf(context.autofillAppMatches, context.autofillWebMatches)) { for ((key, value) in prefs.all) { if (!key.startsWith(PREFERENCE_PREFIX_MATCHES)) continue diff --git a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillPreferences.kt b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillPreferences.kt index c6cdffed..fdbd15af 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillPreferences.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillPreferences.kt @@ -96,7 +96,8 @@ enum class DirectoryStructure(val value: String) { when (this) { EncryptedUsername -> null FileBased -> file.nameWithoutExtension.takeIf { file.parentFile != null } - DirectoryBased -> file.parentFile?.let { parentFile -> "${parentFile.name}/${file.nameWithoutExtension}" } + DirectoryBased -> + file.parentFile?.let { parentFile -> "${parentFile.name}/${file.nameWithoutExtension}" } ?: file.nameWithoutExtension } @@ -138,7 +139,8 @@ object AutofillPreferences { directoryStructure: DirectoryStructure ): Credentials { // Always give priority to a username stored in the encrypted extras - val username = entry.username ?: directoryStructure.getUsernameFor(file) ?: context.getDefaultUsername() + val username = + entry.username ?: directoryStructure.getUsernameFor(file) ?: context.getDefaultUsername() return Credentials(username, entry.password, entry.totp.value) } } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillResponseBuilder.kt b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillResponseBuilder.kt index d8126438..9dabf914 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillResponseBuilder.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillResponseBuilder.kt @@ -154,7 +154,10 @@ class AutofillResponseBuilder(form: FillableForm) { if (datasetCount == 0) return null if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { setHeader( - makeRemoteView(context, makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true))) + makeRemoteView( + context, + makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)) + ) ) } makeSaveInfo()?.let { setSaveInfo(it) } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillViewUtils.kt b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillViewUtils.kt index 46f7d821..1d09d001 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillViewUtils.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/autofill/AutofillViewUtils.kt @@ -51,13 +51,15 @@ fun makeInlinePresentation( if (UiVersions.INLINE_UI_VERSION_1 !in UiVersions.getVersions(imeSpec.style)) return null - val launchIntent = PendingIntent.getActivity(context, 0, Intent(context, PasswordStore::class.java), 0) + val launchIntent = + PendingIntent.getActivity(context, 0, Intent(context, PasswordStore::class.java), 0) val slice = InlineSuggestionUi.newContentBuilder(launchIntent).run { setTitle(metadata.title) if (metadata.subtitle != null) setSubtitle(metadata.subtitle) setContentDescription( - if (metadata.subtitle != null) "${metadata.title} - ${metadata.subtitle}" else metadata.title + if (metadata.subtitle != null) "${metadata.title} - ${metadata.subtitle}" + else metadata.title ) setStartIcon(Icon.createWithResource(context, metadata.iconRes)) build().slice @@ -69,13 +71,19 @@ fun makeInlinePresentation( fun makeFillMatchMetadata(context: Context, file: File): DatasetMetadata { val directoryStructure = AutofillPreferences.directoryStructure(context) val relativeFile = file.relativeTo(PasswordRepository.getRepositoryDirectory()) - val title = directoryStructure.getIdentifierFor(relativeFile) ?: directoryStructure.getAccountPartFor(relativeFile)!! + val title = + directoryStructure.getIdentifierFor(relativeFile) + ?: directoryStructure.getAccountPartFor(relativeFile)!! val subtitle = directoryStructure.getAccountPartFor(relativeFile) return DatasetMetadata(title, subtitle, R.drawable.ic_person_black_24dp) } fun makeSearchAndFillMetadata(context: Context) = - DatasetMetadata(context.getString(R.string.oreo_autofill_search_in_store), null, R.drawable.ic_search_black_24dp) + DatasetMetadata( + context.getString(R.string.oreo_autofill_search_in_store), + null, + R.drawable.ic_search_black_24dp + ) fun makeGenerateAndFillMetadata(context: Context) = DatasetMetadata( @@ -85,7 +93,11 @@ fun makeGenerateAndFillMetadata(context: Context) = ) fun makeFillOtpFromSmsMetadata(context: Context) = - DatasetMetadata(context.getString(R.string.oreo_autofill_fill_otp_from_sms), null, R.drawable.ic_autofill_sms) + DatasetMetadata( + context.getString(R.string.oreo_autofill_fill_otp_from_sms), + null, + R.drawable.ic_autofill_sms + ) fun makeEmptyMetadata() = DatasetMetadata("PLACEHOLDER", "PLACEHOLDER", R.mipmap.ic_launcher) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/crypto/GpgIdentifier.kt b/app/src/main/java/dev/msfjarvis/aps/util/crypto/GpgIdentifier.kt index cc759e9a..f99b623c 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/crypto/GpgIdentifier.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/crypto/GpgIdentifier.kt @@ -17,7 +17,8 @@ sealed class GpgIdentifier { if (identifier.isEmpty()) return null // Match long key IDs: // FF22334455667788 or 0xFF22334455667788 - val maybeLongKeyId = identifier.removePrefix("0x").takeIf { it.matches("[a-fA-F0-9]{16}".toRegex()) } + val maybeLongKeyId = + identifier.removePrefix("0x").takeIf { it.matches("[a-fA-F0-9]{16}".toRegex()) } if (maybeLongKeyId != null) { val keyId = maybeLongKeyId.toULong(16) return KeyId(keyId.toLong()) @@ -25,7 +26,8 @@ sealed class GpgIdentifier { // Match fingerprints: // FF223344556677889900112233445566778899 or 0xFF223344556677889900112233445566778899 - val maybeFingerprint = identifier.removePrefix("0x").takeIf { it.matches("[a-fA-F0-9]{40}".toRegex()) } + val maybeFingerprint = + identifier.removePrefix("0x").takeIf { it.matches("[a-fA-F0-9]{40}".toRegex()) } if (maybeFingerprint != null) { // Truncating to the long key ID is not a security issue since OpenKeychain only // accepts diff --git a/app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt b/app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt index 94103118..21cc30bc 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/extensions/AndroidExtensions.kt @@ -41,7 +41,11 @@ fun <T : View> AlertDialog.requestInputFocusOnView(@IdRes id: Int) { setOnShowListener { findViewById<T>(id)?.apply { setOnFocusChangeListener { v, _ -> - v.post { context.getSystemService<InputMethodManager>()?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT) } + v.post { + context + .getSystemService<InputMethodManager>() + ?.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT) + } } requestFocus() } @@ -64,7 +68,8 @@ fun Context.getEncryptedProxyPrefs() = getEncryptedPrefs("http_proxy") /** Get an instance of [EncryptedSharedPreferences] with the given [fileName] */ private fun Context.getEncryptedPrefs(fileName: String): SharedPreferences { - val masterKeyAlias = MasterKey.Builder(applicationContext).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build() + val masterKeyAlias = + MasterKey.Builder(applicationContext).setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build() return EncryptedSharedPreferences.create( applicationContext, fileName, diff --git a/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentViewBindingDelegate.kt b/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentViewBindingDelegate.kt index 5a1b554f..de21a359 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentViewBindingDelegate.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/extensions/FragmentViewBindingDelegate.kt @@ -20,8 +20,10 @@ import kotlin.reflect.KProperty * Imported from * https://medium.com/@Zhuinden/simple-one-liner-viewbinding-in-fragments-and-activities-with-kotlin-961430c6c07c */ -class FragmentViewBindingDelegate<T : ViewBinding>(val fragment: Fragment, val viewBindingFactory: (View) -> T) : - ReadOnlyProperty<Fragment, T> { +class FragmentViewBindingDelegate<T : ViewBinding>( + val fragment: Fragment, + val viewBindingFactory: (View) -> T +) : ReadOnlyProperty<Fragment, T> { private var binding: T? = null @@ -51,7 +53,9 @@ class FragmentViewBindingDelegate<T : ViewBinding>(val fragment: Fragment, val v val lifecycle = fragment.viewLifecycleOwner.lifecycle if (!lifecycle.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) { - throw IllegalStateException("Should not attempt to get bindings when Fragment views are destroyed.") + throw IllegalStateException( + "Should not attempt to get bindings when Fragment views are destroyed." + ) } return viewBindingFactory(thisRef.requireView()).also { this.binding = it } @@ -61,5 +65,6 @@ class FragmentViewBindingDelegate<T : ViewBinding>(val fragment: Fragment, val v fun <T : ViewBinding> Fragment.viewBinding(viewBindingFactory: (View) -> T) = FragmentViewBindingDelegate(this, viewBindingFactory) -inline fun <T : ViewBinding> AppCompatActivity.viewBinding(crossinline bindingInflater: (LayoutInflater) -> T) = - lazy(LazyThreadSafetyMode.NONE) { bindingInflater.invoke(layoutInflater) } +inline fun <T : ViewBinding> AppCompatActivity.viewBinding( + crossinline bindingInflater: (LayoutInflater) -> T +) = lazy(LazyThreadSafetyMode.NONE) { bindingInflater.invoke(layoutInflater) } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/ErrorMessages.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/ErrorMessages.kt index 04809fdd..36dc445f 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/ErrorMessages.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/ErrorMessages.kt @@ -14,7 +14,8 @@ import java.net.UnknownHostException /** * Supertype for all Git-related [Exception] s that can be thrown by [GitCommandExecutor.execute]. */ -sealed class GitException(@StringRes res: Int, vararg fmt: String) : Exception(buildMessage(res, *fmt)) { +sealed class GitException(@StringRes res: Int, vararg fmt: String) : + Exception(buildMessage(res, *fmt)) { override val message = super.message!! diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommandExecutor.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommandExecutor.kt index 4546aee1..7be06385 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommandExecutor.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommandExecutor.kt @@ -74,11 +74,13 @@ class GitCommandExecutor( // Code imported (modified) from Gerrit PushOp, license Apache v2 for (rru in result.remoteUpdates) { when (rru.status) { - RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD -> throw PushException.NonFastForward + RemoteRefUpdate.Status.REJECTED_NONFASTFORWARD -> + throw PushException.NonFastForward RemoteRefUpdate.Status.REJECTED_NODELETE, RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED, RemoteRefUpdate.Status.NON_EXISTING, - RemoteRefUpdate.Status.NOT_ATTEMPTED, -> throw PushException.Generic(rru.status.name) + RemoteRefUpdate.Status.NOT_ATTEMPTED, -> + throw PushException.Generic(rru.status.name) RemoteRefUpdate.Status.REJECTED_OTHER_REASON -> { throw if ("non-fast-forward" == rru.message) { PushException.RemoteRejected diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommit.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommit.kt index 68b1c167..490f5e2c 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommit.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/GitCommit.kt @@ -15,4 +15,9 @@ import java.util.Date * @property authorName name of the commit's author without email address. * @property time time when the commit was created. */ -data class GitCommit(val hash: String, val shortMessage: String, val authorName: String, val time: Date) +data class GitCommit( + val hash: String, + val shortMessage: String, + val authorName: String, + val time: Date +) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/GitLogModel.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/GitLogModel.kt index 1ba65086..bfef2571 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/GitLogModel.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/GitLogModel.kt @@ -40,7 +40,9 @@ class GitLogModel { // Additionally, tests with 1000 commits in the log have not produced a significant delay in the // user experience. private val cache: MutableList<GitCommit> by lazy(LazyThreadSafetyMode.NONE) { - commits().map { GitCommit(it.hash, it.shortMessage, it.authorIdent.name, it.time) }.toMutableList() + commits() + .map { GitCommit(it.hash, it.shortMessage, it.authorIdent.name, it.time) } + .toMutableList() } val size = cache.size diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/BreakOutOfDetached.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/BreakOutOfDetached.kt index 196d6d48..fd0aedf7 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/BreakOutOfDetached.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/BreakOutOfDetached.kt @@ -11,13 +11,17 @@ import org.eclipse.jgit.api.RebaseCommand import org.eclipse.jgit.api.ResetCommand import org.eclipse.jgit.lib.RepositoryState -class BreakOutOfDetached(callingActivity: ContinuationContainerActivity) : GitOperation(callingActivity) { +class BreakOutOfDetached(callingActivity: ContinuationContainerActivity) : + GitOperation(callingActivity) { private val merging = repository.repositoryState == RepositoryState.MERGING private val resetCommands = arrayOf( // git checkout -b conflict-branch - git.checkout().setCreateBranch(true).setName("conflicting-$remoteBranch-${System.currentTimeMillis()}"), + git + .checkout() + .setCreateBranch(true) + .setName("conflicting-$remoteBranch-${System.currentTimeMillis()}"), // push the changes git.push().setRemote("origin"), // switch back to ${gitBranch} @@ -47,8 +51,12 @@ class BreakOutOfDetached(callingActivity: ContinuationContainerActivity) : GitOp if (!git.repository.repositoryState.isRebasing && !merging) { MaterialAlertDialogBuilder(callingActivity) .setTitle(callingActivity.resources.getString(R.string.git_abort_and_push_title)) - .setMessage(callingActivity.resources.getString(R.string.git_break_out_of_detached_unneeded)) - .setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> callingActivity.finish() } + .setMessage( + callingActivity.resources.getString(R.string.git_break_out_of_detached_unneeded) + ) + .setPositiveButton(callingActivity.resources.getString(R.string.dialog_ok)) { _, _ -> + callingActivity.finish() + } .show() false } else { diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/CloneOperation.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/CloneOperation.kt index a5a4f5d0..75db2ea5 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/CloneOperation.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/CloneOperation.kt @@ -14,7 +14,8 @@ import org.eclipse.jgit.api.GitCommand * @param uri URL to clone the repository from * @param callingActivity the calling activity */ -class CloneOperation(callingActivity: ContinuationContainerActivity, uri: String) : GitOperation(callingActivity) { +class CloneOperation(callingActivity: ContinuationContainerActivity, uri: String) : + GitOperation(callingActivity) { override val commands: Array<GitCommand<out Any>> = arrayOf( diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/CredentialFinder.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/CredentialFinder.kt index 40869cf2..e06cc996 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/CredentialFinder.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/CredentialFinder.kt @@ -24,7 +24,8 @@ import dev.msfjarvis.aps.util.settings.PreferenceKeys import kotlin.coroutines.Continuation import kotlin.coroutines.resume -class CredentialFinder(val callingActivity: FragmentActivity, val authMode: AuthMode) : InteractivePasswordFinder() { +class CredentialFinder(val callingActivity: FragmentActivity, val authMode: AuthMode) : + InteractivePasswordFinder() { override fun askForPassword(cont: Continuation<String?>, isRetry: Boolean) { val gitOperationPrefs = callingActivity.getEncryptedGitPrefs() @@ -49,18 +50,22 @@ class CredentialFinder(val callingActivity: FragmentActivity, val authMode: Auth rememberRes = R.string.git_operation_remember_password errorRes = R.string.git_operation_wrong_password } - else -> throw IllegalStateException("Only SshKey and Password connection mode ask for passwords") + else -> + throw IllegalStateException("Only SshKey and Password connection mode ask for passwords") } if (isRetry) gitOperationPrefs.edit { remove(credentialPref) } val storedCredential = gitOperationPrefs.getString(credentialPref, null) if (storedCredential == null) { val layoutInflater = LayoutInflater.from(callingActivity) - @SuppressLint("InflateParams") val dialogView = layoutInflater.inflate(R.layout.git_credential_layout, null) - val credentialLayout = dialogView.findViewById<TextInputLayout>(R.id.git_auth_passphrase_layout) + @SuppressLint("InflateParams") + val dialogView = layoutInflater.inflate(R.layout.git_credential_layout, null) + val credentialLayout = + dialogView.findViewById<TextInputLayout>(R.id.git_auth_passphrase_layout) val editCredential = dialogView.findViewById<TextInputEditText>(R.id.git_auth_credential) editCredential.setHint(hintRes) - val rememberCredential = dialogView.findViewById<MaterialCheckBox>(R.id.git_auth_remember_credential) + val rememberCredential = + dialogView.findViewById<MaterialCheckBox>(R.id.git_auth_remember_credential) rememberCredential.setText(rememberRes) if (isRetry) { credentialLayout.error = callingActivity.resources.getString(errorRes) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt index 0d0dac9c..dbea37e8 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt @@ -60,7 +60,8 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) { private val authActivity get() = callingActivity as ContinuationContainerActivity - private class HttpsCredentialsProvider(private val passwordFinder: PasswordFinder) : CredentialsProvider() { + private class HttpsCredentialsProvider(private val passwordFinder: PasswordFinder) : + CredentialsProvider() { private var cachedPassword: CharArray? = null @@ -72,7 +73,8 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) { is CredentialItem.Username -> item.value = uri?.user is CredentialItem.Password -> { item.value = - cachedPassword?.clone() ?: passwordFinder.reqPassword(null).also { cachedPassword = it.clone() } + cachedPassword?.clone() + ?: passwordFinder.reqPassword(null).also { cachedPassword = it.clone() } } else -> UnsupportedCredentialItem(uri, item.javaClass.name) } @@ -102,7 +104,10 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) { .onFailure { e -> e(e) } } - private fun registerAuthProviders(authMethod: SshAuthMethod, credentialsProvider: CredentialsProvider? = null) { + private fun registerAuthProviders( + authMethod: SshAuthMethod, + credentialsProvider: CredentialsProvider? = null + ) { sshSessionFactory = SshjSessionFactory(authMethod, hostKeyFile) commands.filterIsInstance<TransportCommand<*, *>>().forEach { command -> command.setTransportConfigCallback { transport: Transport -> @@ -132,12 +137,12 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) { MaterialAlertDialogBuilder(callingActivity) .setMessage(callingActivity.resources.getString(R.string.ssh_preferences_dialog_text)) .setTitle(callingActivity.resources.getString(R.string.ssh_preferences_dialog_title)) - .setPositiveButton(callingActivity.resources.getString(R.string.ssh_preferences_dialog_import)) { _, _ -> - getSshKey(false) - } - .setNegativeButton(callingActivity.resources.getString(R.string.ssh_preferences_dialog_generate)) { _, _ -> - getSshKey(true) - } + .setPositiveButton( + callingActivity.resources.getString(R.string.ssh_preferences_dialog_import) + ) { _, _ -> getSshKey(false) } + .setNegativeButton( + callingActivity.resources.getString(R.string.ssh_preferences_dialog_generate) + ) { _, _ -> getSshKey(true) } .setNeutralButton(callingActivity.resources.getString(R.string.dialog_cancel)) { _, _ -> // Finish the blank GitActivity so user doesn't have to press back callingActivity.finish() @@ -153,9 +158,10 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) { val result = withContext(Dispatchers.Main) { suspendCoroutine<BiometricAuthenticator.Result> { cont -> - BiometricAuthenticator.authenticate(callingActivity, R.string.biometric_prompt_title_ssh_auth) { - if (it !is BiometricAuthenticator.Result.Failure) cont.resume(it) - } + BiometricAuthenticator.authenticate( + callingActivity, + R.string.biometric_prompt_title_ssh_auth + ) { if (it !is BiometricAuthenticator.Result.Failure) cont.resume(it) } } } when (result) { @@ -193,7 +199,8 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) { } AuthMode.OpenKeychain -> registerAuthProviders(SshAuthMethod.OpenKeychain(authActivity)) AuthMode.Password -> { - val httpsCredentialProvider = HttpsCredentialsProvider(CredentialFinder(callingActivity, AuthMode.Password)) + val httpsCredentialProvider = + HttpsCredentialsProvider(CredentialFinder(callingActivity, AuthMode.Password)) registerAuthProviders(SshAuthMethod.Password(authActivity), httpsCredentialProvider) } AuthMode.None -> {} diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/PushOperation.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/PushOperation.kt index a9f168ad..14f16164 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/PushOperation.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/PushOperation.kt @@ -7,7 +7,8 @@ package dev.msfjarvis.aps.util.git.operation import dev.msfjarvis.aps.util.git.sshj.ContinuationContainerActivity import org.eclipse.jgit.api.GitCommand -class PushOperation(callingActivity: ContinuationContainerActivity) : GitOperation(callingActivity) { +class PushOperation(callingActivity: ContinuationContainerActivity) : + GitOperation(callingActivity) { override val commands: Array<GitCommand<out Any>> = arrayOf( diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/ResetToRemoteOperation.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/ResetToRemoteOperation.kt index dccd69b0..16114f65 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/ResetToRemoteOperation.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/ResetToRemoteOperation.kt @@ -7,7 +7,8 @@ package dev.msfjarvis.aps.util.git.operation import dev.msfjarvis.aps.util.git.sshj.ContinuationContainerActivity import org.eclipse.jgit.api.ResetCommand -class ResetToRemoteOperation(callingActivity: ContinuationContainerActivity) : GitOperation(callingActivity) { +class ResetToRemoteOperation(callingActivity: ContinuationContainerActivity) : + GitOperation(callingActivity) { override val commands = arrayOf( diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/OpenKeychainKeyProvider.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/OpenKeychainKeyProvider.kt index acb7d8d7..d726c353 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/OpenKeychainKeyProvider.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/OpenKeychainKeyProvider.kt @@ -106,7 +106,8 @@ class OpenKeychainKeyProvider private constructor(val activity: ContinuationCont val response = sshPublicKeyResponse.response as SshPublicKeyResponse val sshPublicKey = response.sshPublicKey!! publicKey = - parseSshPublicKey(sshPublicKey) ?: throw IllegalStateException("OpenKeychain API returned invalid SSH key") + parseSshPublicKey(sshPublicKey) + ?: throw IllegalStateException("OpenKeychain API returned invalid SSH key") } is ApiResponse.NoSuchKey -> if (isRetry) { @@ -122,13 +123,17 @@ class OpenKeychainKeyProvider private constructor(val activity: ContinuationCont private suspend fun selectKey() { when (val keySelectionResponse = executeApiRequest(KeySelectionRequest())) { - is ApiResponse.Success -> keyId = (keySelectionResponse.response as KeySelectionResponse).keyId + is ApiResponse.Success -> + keyId = (keySelectionResponse.response as KeySelectionResponse).keyId is ApiResponse.GeneralError -> throw keySelectionResponse.exception is ApiResponse.NoSuchKey -> throw keySelectionResponse.exception } } - private suspend fun executeApiRequest(request: Request, resultOfUserInteraction: Intent? = null): ApiResponse { + private suspend fun executeApiRequest( + request: Request, + resultOfUserInteraction: Intent? = null + ): ApiResponse { d { "executeRequest($request) called" } val result = withContext(Dispatchers.Main) { @@ -141,7 +146,11 @@ class OpenKeychainKeyProvider private constructor(val activity: ContinuationCont } private suspend fun parseResult(request: Request, result: Intent): ApiResponse { - return when (result.getIntExtra(SshAuthenticationApi.EXTRA_RESULT_CODE, SshAuthenticationApi.RESULT_CODE_ERROR)) { + return when (result.getIntExtra( + SshAuthenticationApi.EXTRA_RESULT_CODE, + SshAuthenticationApi.RESULT_CODE_ERROR + ) + ) { SshAuthenticationApi.RESULT_CODE_SUCCESS -> { ApiResponse.Success( when (request) { @@ -153,20 +162,27 @@ class OpenKeychainKeyProvider private constructor(val activity: ContinuationCont ) } SshAuthenticationApi.RESULT_CODE_USER_INTERACTION_REQUIRED -> { - val pendingIntent: PendingIntent = result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT)!! + val pendingIntent: PendingIntent = + result.getParcelableExtra(SshAuthenticationApi.EXTRA_PENDING_INTENT)!! val resultOfUserInteraction: Intent = withContext(Dispatchers.Main) { suspendCoroutine { cont -> activity.stashedCont = cont - activity.continueAfterUserInteraction.launch(IntentSenderRequest.Builder(pendingIntent).build()) + activity.continueAfterUserInteraction.launch( + IntentSenderRequest.Builder(pendingIntent).build() + ) } } executeApiRequest(request, resultOfUserInteraction) } else -> { - val error = result.getParcelableExtra<SshAuthenticationApiError>(SshAuthenticationApi.EXTRA_ERROR) + val error = + result.getParcelableExtra<SshAuthenticationApiError>(SshAuthenticationApi.EXTRA_ERROR) val exception = - UserAuthException(DisconnectReason.UNKNOWN, "Request ${request::class.simpleName} failed: ${error?.message}") + UserAuthException( + DisconnectReason.UNKNOWN, + "Request ${request::class.simpleName} failed: ${error?.message}" + ) when (error?.error) { SshAuthenticationApiError.NO_AUTH_KEY, SshAuthenticationApiError.NO_SUCH_KEY -> ApiResponse.NoSuchKey(exception) @@ -181,7 +197,9 @@ class OpenKeychainKeyProvider private constructor(val activity: ContinuationCont privateKey = object : OpenKeychainPrivateKey { override suspend fun sign(challenge: ByteArray, hashAlgorithm: Int) = - when (val signingResponse = executeApiRequest(SigningRequest(challenge, keyId, hashAlgorithm))) { + when (val signingResponse = + executeApiRequest(SigningRequest(challenge, keyId, hashAlgorithm)) + ) { is ApiResponse.Success -> (signingResponse.response as SigningResponse).signature is ApiResponse.GeneralError -> throw signingResponse.exception is ApiResponse.NoSuchKey -> throw signingResponse.exception diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/OpenKeychainWrappedKeyAlgorithmFactory.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/OpenKeychainWrappedKeyAlgorithmFactory.kt index 0ab01ba5..56831b1d 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/OpenKeychainWrappedKeyAlgorithmFactory.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/OpenKeychainWrappedKeyAlgorithmFactory.kt @@ -28,7 +28,8 @@ class OpenKeychainWrappedKeyAlgorithmFactory(private val factory: Factory.Named< override fun create() = OpenKeychainWrappedKeyAlgorithm(factory.create()) } -class OpenKeychainWrappedKeyAlgorithm(private val keyAlgorithm: KeyAlgorithm) : KeyAlgorithm by keyAlgorithm { +class OpenKeychainWrappedKeyAlgorithm(private val keyAlgorithm: KeyAlgorithm) : + KeyAlgorithm by keyAlgorithm { private val hashAlgorithm = when (keyAlgorithm.keyAlgorithm) { @@ -39,11 +40,14 @@ class OpenKeychainWrappedKeyAlgorithm(private val keyAlgorithm: KeyAlgorithm) : else -> SshAuthenticationApi.SHA512 } - override fun newSignature() = OpenKeychainWrappedSignature(keyAlgorithm.newSignature(), hashAlgorithm) + override fun newSignature() = + OpenKeychainWrappedSignature(keyAlgorithm.newSignature(), hashAlgorithm) } -class OpenKeychainWrappedSignature(private val wrappedSignature: Signature, private val hashAlgorithm: Int) : - Signature by wrappedSignature { +class OpenKeychainWrappedSignature( + private val wrappedSignature: Signature, + private val hashAlgorithm: Int +) : Signature by wrappedSignature { private val data = ByteArrayOutputStream() diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshKey.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshKey.kt index 37414707..3d23658e 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshKey.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshKey.kt @@ -115,7 +115,8 @@ object SshKey { private var type: Type? get() = Type.fromValue(context.sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_KEY_TYPE)) - set(value) = context.sharedPrefs.edit { putString(PreferenceKeys.GIT_REMOTE_KEY_TYPE, value?.value) } + set(value) = + context.sharedPrefs.edit { putString(PreferenceKeys.GIT_REMOTE_KEY_TYPE, value?.value) } private val isStrongBoxSupported by lazy(LazyThreadSafetyMode.NONE) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) @@ -138,13 +139,20 @@ object SshKey { } } - enum class Algorithm(val algorithm: String, val applyToSpec: KeyGenParameterSpec.Builder.() -> Unit) { + enum class Algorithm( + val algorithm: String, + val applyToSpec: KeyGenParameterSpec.Builder.() -> Unit + ) { Rsa( KeyProperties.KEY_ALGORITHM_RSA, { setKeySize(3072) setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) - setDigests(KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512) + setDigests( + KeyProperties.DIGEST_SHA1, + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA512 + ) } ), Ecdsa( @@ -163,7 +171,9 @@ object SshKey { private fun delete() { androidKeystore.deleteEntry(KEYSTORE_ALIAS) // Remove Tink key set used by AndroidX's EncryptedFile. - context.getSharedPreferences(ANDROIDX_SECURITY_KEYSET_PREF_NAME, Context.MODE_PRIVATE).edit { clear() } + context.getSharedPreferences(ANDROIDX_SECURITY_KEYSET_PREF_NAME, Context.MODE_PRIVATE).edit { + clear() + } if (privateKeyFile.isFile) { privateKeyFile.delete() } @@ -177,7 +187,8 @@ object SshKey { fun import(uri: Uri) { // First check whether the content at uri is likely an SSH private key. val fileSize = - context.contentResolver.query(uri, arrayOf(OpenableColumns.SIZE), null, null, null)?.use { cursor -> + context.contentResolver.query(uri, arrayOf(OpenableColumns.SIZE), null, null, null)?.use { + cursor -> // Cursor returns only a single row. cursor.moveToFirst() cursor.getInt(0) @@ -186,7 +197,9 @@ object SshKey { // We assume that an SSH key's ideal size is > 0 bytes && < 100 kilobytes. if (fileSize > 100_000 || fileSize == 0) - throw IllegalArgumentException(context.getString(R.string.ssh_key_import_error_not_an_ssh_key_message)) + throw IllegalArgumentException( + context.getString(R.string.ssh_key_import_error_not_an_ssh_key_message) + ) val sshKeyInputStream = context.contentResolver.openInputStream(uri) @@ -199,7 +212,9 @@ object SshKey { !Regex("BEGIN .* PRIVATE KEY").containsMatchIn(lines.first()) || !Regex("END .* PRIVATE KEY").containsMatchIn(lines.last()) ) - throw IllegalArgumentException(context.getString(R.string.ssh_key_import_error_not_an_ssh_key_message)) + throw IllegalArgumentException( + context.getString(R.string.ssh_key_import_error_not_an_ssh_key_message) + ) // At this point, we are reasonably confident that we have actually been provided a private // key and delete the old key. @@ -249,7 +264,9 @@ object SshKey { val encryptedPrivateKeyFile = getOrCreateWrappedPrivateKeyFile(requireAuthentication) // Generate the ed25519 key pair and encrypt the private key. val keyPair = net.i2p.crypto.eddsa.KeyPairGenerator().generateKeyPair() - encryptedPrivateKeyFile.openFileOutput().use { os -> os.write((keyPair.private as EdDSAPrivateKey).seed) } + encryptedPrivateKeyFile.openFileOutput().use { os -> + os.write((keyPair.private as EdDSAPrivateKey).seed) + } // Write public key in SSH format to .ssh_key.pub. publicKeyFile.writeText(toSshPublicKey(keyPair.public)) @@ -288,7 +305,8 @@ object SshKey { fun provide(client: SSHClient, passphraseFinder: InteractivePasswordFinder): KeyProvider? = when (type) { - Type.LegacyGenerated, Type.Imported -> client.loadKeys(privateKeyFile.absolutePath, passphraseFinder) + Type.LegacyGenerated, Type.Imported -> + client.loadKeys(privateKeyFile.absolutePath, passphraseFinder) Type.KeystoreNative -> KeystoreNativeKeyProvider Type.KeystoreWrappedEd25519 -> KeystoreWrappedEd25519KeyProvider null -> null @@ -305,7 +323,10 @@ object SshKey { override fun getPrivate(): PrivateKey = runCatching { androidKeystore.sshPrivateKey!! }.getOrElse { error -> e(error) - throw IOException("Failed to access private key '$KEYSTORE_ALIAS' from Android Keystore", error) + throw IOException( + "Failed to access private key '$KEYSTORE_ALIAS' from Android Keystore", + error + ) } override fun getType(): KeyType = KeyType.fromKey(public) @@ -326,7 +347,9 @@ object SshKey { // for `requireAuthentication` is not used as the key already exists at this point. val encryptedPrivateKeyFile = runBlocking { getOrCreateWrappedPrivateKeyFile(false) } val rawPrivateKey = encryptedPrivateKeyFile.openFileInput().use { it.readBytes() } - EdDSAPrivateKey(EdDSAPrivateKeySpec(rawPrivateKey, EdDSANamedCurveTable.ED_25519_CURVE_SPEC)) + EdDSAPrivateKey( + EdDSAPrivateKeySpec(rawPrivateKey, EdDSANamedCurveTable.ED_25519_CURVE_SPEC) + ) } .getOrElse { error -> e(error) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshjConfig.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshjConfig.kt index e93787f4..f8053ef3 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshjConfig.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshjConfig.kt @@ -37,7 +37,8 @@ fun setUpBouncyCastleForSshj() { // Replace the Android BC provider with the Java BouncyCastle provider since the former does // not include all the required algorithms. // Note: This may affect crypto operations in other parts of the application. - val bcIndex = Security.getProviders().indexOfFirst { it.name == BouncyCastleProvider.PROVIDER_NAME } + val bcIndex = + Security.getProviders().indexOfFirst { it.name == BouncyCastleProvider.PROVIDER_NAME } if (bcIndex == -1) { // No Android BC found, install Java BC at lowest priority. Security.addProvider(BouncyCastleProvider()) @@ -77,9 +78,11 @@ private abstract class AbstractLogger(private val name: String) : Logger { override fun trace(msg: String, t: Throwable?) = t(msg, t) override fun trace(marker: Marker, msg: String) = trace(msg) override fun trace(marker: Marker?, format: String, arg: Any?) = trace(format, arg) - override fun trace(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = trace(format, arg1, arg2) + override fun trace(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = + trace(format, arg1, arg2) - override fun trace(marker: Marker?, format: String, vararg arguments: Any?) = trace(format, *arguments) + override fun trace(marker: Marker?, format: String, vararg arguments: Any?) = + trace(format, *arguments) override fun trace(marker: Marker?, msg: String, t: Throwable?) = trace(msg, t) @@ -90,9 +93,11 @@ private abstract class AbstractLogger(private val name: String) : Logger { override fun debug(msg: String, t: Throwable?) = d(msg, t) override fun debug(marker: Marker, msg: String) = debug(msg) override fun debug(marker: Marker?, format: String, arg: Any?) = debug(format, arg) - override fun debug(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = debug(format, arg1, arg2) + override fun debug(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = + debug(format, arg1, arg2) - override fun debug(marker: Marker?, format: String, vararg arguments: Any?) = debug(format, *arguments) + override fun debug(marker: Marker?, format: String, vararg arguments: Any?) = + debug(format, *arguments) override fun debug(marker: Marker?, msg: String, t: Throwable?) = debug(msg, t) @@ -103,9 +108,11 @@ private abstract class AbstractLogger(private val name: String) : Logger { override fun info(msg: String, t: Throwable?) = i(msg, t) override fun info(marker: Marker, msg: String) = info(msg) override fun info(marker: Marker?, format: String, arg: Any?) = info(format, arg) - override fun info(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = info(format, arg1, arg2) + override fun info(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = + info(format, arg1, arg2) - override fun info(marker: Marker?, format: String, vararg arguments: Any?) = info(format, *arguments) + override fun info(marker: Marker?, format: String, vararg arguments: Any?) = + info(format, *arguments) override fun info(marker: Marker?, msg: String, t: Throwable?) = info(msg, t) @@ -116,9 +123,11 @@ private abstract class AbstractLogger(private val name: String) : Logger { override fun warn(msg: String, t: Throwable?) = w(msg, t) override fun warn(marker: Marker, msg: String) = warn(msg) override fun warn(marker: Marker?, format: String, arg: Any?) = warn(format, arg) - override fun warn(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = warn(format, arg1, arg2) + override fun warn(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = + warn(format, arg1, arg2) - override fun warn(marker: Marker?, format: String, vararg arguments: Any?) = warn(format, *arguments) + override fun warn(marker: Marker?, format: String, vararg arguments: Any?) = + warn(format, *arguments) override fun warn(marker: Marker?, msg: String, t: Throwable?) = warn(msg, t) @@ -129,9 +138,11 @@ private abstract class AbstractLogger(private val name: String) : Logger { override fun error(msg: String, t: Throwable?) = e(msg, t) override fun error(marker: Marker, msg: String) = error(msg) override fun error(marker: Marker?, format: String, arg: Any?) = error(format, arg) - override fun error(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = error(format, arg1, arg2) + override fun error(marker: Marker?, format: String, arg1: Any?, arg2: Any?) = + error(format, arg1, arg2) - override fun error(marker: Marker?, format: String, vararg arguments: Any?) = error(format, *arguments) + override fun error(marker: Marker?, format: String, vararg arguments: Any?) = + error(format, *arguments) override fun error(marker: Marker?, msg: String, t: Throwable?) = error(msg, t) } @@ -148,7 +159,8 @@ object TimberLoggerFactory : LoggerFactory { // Replace slf4j's "{}" format string style with standard Java's "%s". // The supposedly redundant escape on the } is not redundant. - @Suppress("RegExpRedundantEscape") private fun String.fix() = replace("""(?!<\\)\{\}""".toRegex(), "%s") + @Suppress("RegExpRedundantEscape") + 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) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshjSessionFactory.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshjSessionFactory.kt index 95676d7f..bc068f52 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshjSessionFactory.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/git/sshj/SshjSessionFactory.kt @@ -52,7 +52,10 @@ abstract class InteractivePasswordFinder : PasswordFinder { abstract fun askForPassword(cont: Continuation<String?>, isRetry: Boolean) final override fun reqPassword(resource: Resource<*>?): CharArray { - val password = runBlocking(Dispatchers.Main) { suspendCoroutine<String?> { cont -> askForPassword(cont, isRetry) } } + val password = + runBlocking(Dispatchers.Main) { + suspendCoroutine<String?> { cont -> askForPassword(cont, isRetry) } + } isRetry = true return password?.toCharArray() ?: throw SSHException(DisconnectReason.AUTH_CANCELLED_BY_USER) } @@ -60,11 +63,17 @@ abstract class InteractivePasswordFinder : PasswordFinder { final override fun shouldRetry(resource: Resource<*>?) = true } -class SshjSessionFactory(private val authMethod: SshAuthMethod, private val hostKeyFile: File) : SshSessionFactory() { +class SshjSessionFactory(private val authMethod: SshAuthMethod, private val hostKeyFile: File) : + SshSessionFactory() { private var currentSession: SshjSession? = null - override fun getSession(uri: URIish, credentialsProvider: CredentialsProvider?, fs: FS?, tms: Int): RemoteSession { + override fun getSession( + uri: URIish, + credentialsProvider: CredentialsProvider?, + fs: FS?, + tms: Int + ): RemoteSession { return currentSession ?: SshjSession(uri, uri.user, authMethod, hostKeyFile).connect().also { d { "New SSH connection created" } @@ -81,7 +90,9 @@ private fun makeTofuHostKeyVerifier(hostKeyFile: File): HostKeyVerifier { if (!hostKeyFile.exists()) { return HostKeyVerifier { _, _, key -> val digest = - runCatching { SecurityUtils.getMessageDigest("SHA-256") }.getOrElse { e -> throw SSHRuntimeException(e) } + runCatching { SecurityUtils.getMessageDigest("SHA-256") }.getOrElse { e -> + throw SSHRuntimeException(e) + } digest.update(PlainBuffer().putPublicKey(key).compactData) val digestData = digest.digest() val hostKeyEntry = "SHA256:${Base64.encodeToString(digestData, Base64.NO_WRAP)}" @@ -115,7 +126,9 @@ private class SshjSession( 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}" } } + uri.setUser(realUser).setHost(realHost).also { + d { "After fixup: user=${it.user}, host=${it.host}" } + } } else { uri } @@ -131,7 +144,8 @@ private class SshjSession( ssh.auth(username, passwordAuth) } is SshAuthMethod.SshKey -> { - val pubkeyAuth = AuthPublickey(SshKey.provide(ssh, CredentialFinder(authMethod.activity, AuthMode.SshKey))) + val pubkeyAuth = + AuthPublickey(SshKey.provide(ssh, CredentialFinder(authMethod.activity, AuthMode.SshKey))) ssh.auth(username, pubkeyAuth, passwordAuth) } is SshAuthMethod.OpenKeychain -> { @@ -174,7 +188,8 @@ private class SshjSession( } } -private class SshjProcess(private val command: Session.Command, private val timeout: Long) : Process() { +private class SshjProcess(private val command: Session.Command, private val timeout: Long) : + Process() { override fun waitFor(): Int { command.join(timeout, TimeUnit.SECONDS) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/pwgen/PasswordGenerator.kt b/app/src/main/java/dev/msfjarvis/aps/util/pwgen/PasswordGenerator.kt index 8199ebfc..bd21ea0a 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/pwgen/PasswordGenerator.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/pwgen/PasswordGenerator.kt @@ -42,7 +42,10 @@ object PasswordGenerator { */ fun setPrefs(ctx: Context, options: List<PasswordOption>, targetLength: Int): Boolean { ctx.getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE).edit { - for (possibleOption in PasswordOption.values()) putBoolean(possibleOption.key, possibleOption in options) + for (possibleOption in PasswordOption.values()) putBoolean( + possibleOption.key, + possibleOption in options + ) putInt("length", targetLength) } return true @@ -82,7 +85,9 @@ object PasswordGenerator { } else { // The No* options are false, so the respective character category will be included. when (option) { - PasswordOption.NoDigits, PasswordOption.NoUppercaseLetters, PasswordOption.NoLowercaseLetters -> { + PasswordOption.NoDigits, + PasswordOption.NoUppercaseLetters, + PasswordOption.NoLowercaseLetters -> { numCharacterCategories++ } PasswordOption.NoAmbiguousCharacters, @@ -98,7 +103,9 @@ object PasswordGenerator { throw PasswordGeneratorException(ctx.resources.getString(R.string.pwgen_no_chars_error)) } if (length < numCharacterCategories) { - throw PasswordGeneratorException(ctx.resources.getString(R.string.pwgen_length_too_short_error)) + throw PasswordGeneratorException( + ctx.resources.getString(R.string.pwgen_length_too_short_error) + ) } if (!(pwgenFlags hasFlag UPPERS) && !(pwgenFlags hasFlag LOWERS)) { phonemes = false @@ -114,7 +121,9 @@ object PasswordGenerator { var iterations = 0 do { if (iterations++ > 1000) - throw PasswordGeneratorException(ctx.resources.getString(R.string.pwgen_max_iterations_exceeded)) + throw PasswordGeneratorException( + ctx.resources.getString(R.string.pwgen_max_iterations_exceeded) + ) password = if (phonemes) { RandomPhonemesGenerator.generate(length, pwgenFlags) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/pwgen/RandomPasswordGenerator.kt b/app/src/main/java/dev/msfjarvis/aps/util/pwgen/RandomPasswordGenerator.kt index e92a753b..c1a8aeb1 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/pwgen/RandomPasswordGenerator.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/pwgen/RandomPasswordGenerator.kt @@ -36,7 +36,9 @@ object RandomPasswordGenerator { var password = "" while (password.length < targetLength) { val candidate = bank.secureRandomCharacter() - if (pwFlags hasFlag PasswordGenerator.NO_AMBIGUOUS && candidate in PasswordGenerator.AMBIGUOUS_STR) { + if (pwFlags hasFlag PasswordGenerator.NO_AMBIGUOUS && + candidate in PasswordGenerator.AMBIGUOUS_STR + ) { continue } password += candidate diff --git a/app/src/main/java/dev/msfjarvis/aps/util/pwgen/RandomPhonemesGenerator.kt b/app/src/main/java/dev/msfjarvis/aps/util/pwgen/RandomPhonemesGenerator.kt index 0b8ca872..5a5f5f21 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/pwgen/RandomPhonemesGenerator.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/pwgen/RandomPhonemesGenerator.kt @@ -100,7 +100,9 @@ object RandomPhonemesGenerator { if (!candidate.flags.hasFlag(nextBasicType) || (isStartOfPart && candidate.flags hasFlag NOT_FIRST) || // Don't let a diphthong that starts with a vowel follow a vowel. - (previousFlags hasFlag VOWEL && candidate.flags hasFlag VOWEL && candidate.flags hasFlag DIPHTHONG) || + (previousFlags hasFlag VOWEL && + candidate.flags hasFlag VOWEL && + candidate.flags hasFlag DIPHTHONG) || // Don't add multi-character candidates if we would go over the targetLength. (password.length + candidate.length > targetLength) || (pwFlags hasFlag PasswordGenerator.NO_AMBIGUOUS && candidate.isAmbiguous) @@ -129,11 +131,15 @@ object RandomPhonemesGenerator { // Second part: Add digits and symbols with a certain probability (if requested) if // they would not directly follow the first character in a pronounceable part. - if (!isStartOfPart && pwFlags hasFlag PasswordGenerator.DIGITS && secureRandomBiasedBoolean(30)) { + if (!isStartOfPart && + pwFlags hasFlag PasswordGenerator.DIGITS && + secureRandomBiasedBoolean(30) + ) { var randomDigit: Char do { randomDigit = secureRandomNumber(10).toString(10).first() - } while (pwFlags hasFlag PasswordGenerator.NO_AMBIGUOUS && randomDigit in PasswordGenerator.AMBIGUOUS_STR) + } while (pwFlags hasFlag PasswordGenerator.NO_AMBIGUOUS && + randomDigit in PasswordGenerator.AMBIGUOUS_STR) password += randomDigit // Begin a new pronounceable part after every digit. @@ -143,11 +149,15 @@ object RandomPhonemesGenerator { continue } - if (!isStartOfPart && pwFlags hasFlag PasswordGenerator.SYMBOLS && secureRandomBiasedBoolean(20)) { + if (!isStartOfPart && + pwFlags hasFlag PasswordGenerator.SYMBOLS && + secureRandomBiasedBoolean(20) + ) { var randomSymbol: Char do { randomSymbol = PasswordGenerator.SYMBOLS_STR.secureRandomCharacter() - } while (pwFlags hasFlag PasswordGenerator.NO_AMBIGUOUS && randomSymbol in PasswordGenerator.AMBIGUOUS_STR) + } while (pwFlags hasFlag PasswordGenerator.NO_AMBIGUOUS && + randomSymbol in PasswordGenerator.AMBIGUOUS_STR) password += randomSymbol // Continue the password generation as if nothing was added. } @@ -157,8 +167,9 @@ object RandomPhonemesGenerator { nextBasicType = when { candidate.flags.hasFlag(CONSONANT) -> VOWEL - previousFlags.hasFlag(VOWEL) || candidate.flags.hasFlag(DIPHTHONG) || secureRandomBiasedBoolean(60) -> - CONSONANT + previousFlags.hasFlag(VOWEL) || + candidate.flags.hasFlag(DIPHTHONG) || + secureRandomBiasedBoolean(60) -> CONSONANT else -> VOWEL } previousFlags = candidate.flags diff --git a/app/src/main/java/dev/msfjarvis/aps/util/pwgenxkpwd/PasswordBuilder.kt b/app/src/main/java/dev/msfjarvis/aps/util/pwgenxkpwd/PasswordBuilder.kt index 3eb2cce7..af8ac5c2 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/pwgenxkpwd/PasswordBuilder.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/pwgenxkpwd/PasswordBuilder.kt @@ -109,7 +109,9 @@ class PasswordBuilder(ctx: Context) { } else candidate CapsType.TitleCase -> - candidate.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + candidate.replaceFirstChar { + if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() + } CapsType.lowercase -> candidate.lowercase(Locale.getDefault()) CapsType.As_iS -> candidate } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/pwgenxkpwd/XkpwdDictionary.kt b/app/src/main/java/dev/msfjarvis/aps/util/pwgenxkpwd/XkpwdDictionary.kt index ab31892f..25162378 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/pwgenxkpwd/XkpwdDictionary.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/pwgenxkpwd/XkpwdDictionary.kt @@ -30,7 +30,10 @@ class XkpwdDictionary(context: Context) { context.resources.openRawResource(R.raw.xkpwdict).bufferedReader().readLines() } - words = lines.asSequence().map { it.trim() }.filter { it.isNotEmpty() && !it.contains(' ') }.groupBy { it.length } + words = + lines.asSequence().map { it.trim() }.filter { it.isNotEmpty() && !it.contains(' ') }.groupBy { + it.length + } } companion object { diff --git a/app/src/main/java/dev/msfjarvis/aps/util/services/ClipboardService.kt b/app/src/main/java/dev/msfjarvis/aps/util/services/ClipboardService.kt index d25a110e..de7d727c 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/services/ClipboardService.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/services/ClipboardService.kt @@ -140,7 +140,10 @@ class ClipboardService : Service() { } @RequiresApi(Build.VERSION_CODES.N) - private fun createNotificationApi24(pendingIntent: PendingIntent, clearTimeMs: Long): Notification { + private fun createNotificationApi24( + pendingIntent: PendingIntent, + clearTimeMs: Long + ): Notification { return NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle(getString(R.string.app_name)) .setContentText(getString(R.string.tap_clear_clipboard)) @@ -157,7 +160,11 @@ class ClipboardService : Service() { private fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val serviceChannel = - NotificationChannel(CHANNEL_ID, getString(R.string.app_name), NotificationManager.IMPORTANCE_LOW) + NotificationChannel( + CHANNEL_ID, + getString(R.string.app_name), + NotificationManager.IMPORTANCE_LOW + ) val manager = getSystemService<NotificationManager>() if (manager != null) { manager.createNotificationChannel(serviceChannel) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/services/OreoAutofillService.kt b/app/src/main/java/dev/msfjarvis/aps/util/services/OreoAutofillService.kt index ce55fe7b..4c75a619 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/services/OreoAutofillService.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/services/OreoAutofillService.kt @@ -60,7 +60,11 @@ class OreoAutofillService : AutofillService() { cachePublicSuffixList(applicationContext) } - override fun onFillRequest(request: FillRequest, cancellationSignal: CancellationSignal, callback: FillCallback) { + override fun onFillRequest( + request: FillRequest, + cancellationSignal: CancellationSignal, + callback: FillCallback + ) { val structure = request.fillContexts.lastOrNull()?.structure ?: run { @@ -93,7 +97,8 @@ class OreoAutofillService : AutofillService() { return } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - Api30AutofillResponseBuilder(formToFill).fillCredentials(this, request.inlineSuggestionsRequest, callback) + Api30AutofillResponseBuilder(formToFill) + .fillCredentials(this, request.inlineSuggestionsRequest, callback) } else { AutofillResponseBuilder(formToFill).fillCredentials(this, callback) } @@ -148,11 +153,13 @@ class OreoAutofillService : AutofillService() { } } -fun Context.getDefaultUsername() = sharedPrefs.getString(PreferenceKeys.OREO_AUTOFILL_DEFAULT_USERNAME) +fun Context.getDefaultUsername() = + sharedPrefs.getString(PreferenceKeys.OREO_AUTOFILL_DEFAULT_USERNAME) fun Context.getCustomSuffixes(): Sequence<String> { - return sharedPrefs.getString(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES)?.splitToSequence('\n')?.filter { - it.isNotBlank() && it.first() != '.' && it.last() != '.' - } + return sharedPrefs + .getString(PreferenceKeys.OREO_AUTOFILL_CUSTOM_PUBLIC_SUFFIXES) + ?.splitToSequence('\n') + ?.filter { it.isNotBlank() && it.first() != '.' && it.last() != '.' } ?: emptySequence() } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/services/PasswordExportService.kt b/app/src/main/java/dev/msfjarvis/aps/util/services/PasswordExportService.kt index 2ecd2287..72f14144 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/services/PasswordExportService.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/services/PasswordExportService.kt @@ -137,7 +137,11 @@ class PasswordExportService : Service() { private fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val serviceChannel = - NotificationChannel(CHANNEL_ID, getString(R.string.app_name), NotificationManager.IMPORTANCE_LOW) + NotificationChannel( + CHANNEL_ID, + getString(R.string.app_name), + NotificationManager.IMPORTANCE_LOW + ) val manager = getSystemService<NotificationManager>() if (manager != null) { manager.createNotificationChannel(serviceChannel) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/settings/GitSettings.kt b/app/src/main/java/dev/msfjarvis/aps/util/settings/GitSettings.kt index 3a508e45..d3c85fa7 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/settings/GitSettings.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/settings/GitSettings.kt @@ -25,7 +25,8 @@ enum class Protocol(val pref: String) { private val map = values().associateBy(Protocol::pref) fun fromString(type: String?): Protocol { - return map[type ?: return Ssh] ?: throw IllegalArgumentException("$type is not a valid Protocol") + return map[type ?: return Ssh] + ?: throw IllegalArgumentException("$type is not a valid Protocol") } } } @@ -41,7 +42,8 @@ enum class AuthMode(val pref: String) { private val map = values().associateBy(AuthMode::pref) fun fromString(type: String?): AuthMode { - return map[type ?: return SshKey] ?: throw IllegalArgumentException("$type is not a valid AuthMode") + return map[type ?: return SshKey] + ?: throw IllegalArgumentException("$type is not a valid AuthMode") } } } @@ -50,12 +52,18 @@ object GitSettings { private const val DEFAULT_BRANCH = "master" - private val settings by lazy(LazyThreadSafetyMode.PUBLICATION) { Application.instance.sharedPrefs } + private val settings by lazy(LazyThreadSafetyMode.PUBLICATION) { + Application.instance.sharedPrefs + } private val encryptedSettings by lazy(LazyThreadSafetyMode.PUBLICATION) { Application.instance.getEncryptedGitPrefs() } - private val proxySettings by lazy(LazyThreadSafetyMode.PUBLICATION) { Application.instance.getEncryptedProxyPrefs() } - private val hostKeyPath by lazy(LazyThreadSafetyMode.NONE) { "${Application.instance.filesDir}/.host_key" } + private val proxySettings by lazy(LazyThreadSafetyMode.PUBLICATION) { + Application.instance.getEncryptedProxyPrefs() + } + private val hostKeyPath by lazy(LazyThreadSafetyMode.NONE) { + "${Application.instance.filesDir}/.host_key" + } var authMode get() = AuthMode.fromString(settings.getString(PreferenceKeys.GIT_REMOTE_AUTH)) diff --git a/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt b/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt index a5612603..b9333617 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/settings/Migrations.kt @@ -60,7 +60,8 @@ private fun migrateToGitUrlBasedConfig(sharedPrefs: SharedPreferences) { val url = when { urlWithFreeEntryScheme.startsWith("https://") -> urlWithFreeEntryScheme - urlWithFreeEntryScheme.startsWith("http://") -> urlWithFreeEntryScheme.replaceFirst("http", "https") + urlWithFreeEntryScheme.startsWith("http://") -> + urlWithFreeEntryScheme.replaceFirst("http", "https") else -> "https://$urlWithFreeEntryScheme" } runCatching { if (URI(url).rawAuthority != null) url else null }.get() @@ -96,7 +97,10 @@ private fun migrateToHideAll(sharedPrefs: SharedPreferences) { private fun migrateToSshKey(context: Context, sharedPrefs: SharedPreferences) { val privateKeyFile = File(context.filesDir, ".ssh_key") - if (sharedPrefs.contains(PreferenceKeys.USE_GENERATED_KEY) && !SshKey.exists && privateKeyFile.exists()) { + if (sharedPrefs.contains(PreferenceKeys.USE_GENERATED_KEY) && + !SshKey.exists && + privateKeyFile.exists() + ) { // Currently uses a private key imported or generated with an old version of Password Store. // Generated keys come with a public key which the user should still be able to view after // the migration (not possible for regular imported keys), hence the special case. diff --git a/app/src/main/java/dev/msfjarvis/aps/util/settings/PasswordSortOrder.kt b/app/src/main/java/dev/msfjarvis/aps/util/settings/PasswordSortOrder.kt index ee678de2..6b48b6a9 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/settings/PasswordSortOrder.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/settings/PasswordSortOrder.kt @@ -18,10 +18,15 @@ enum class PasswordSortOrder(val comparator: java.util.Comparator<PasswordItem>) (p1.type + p1.name).compareTo(p2.type + p2.name, ignoreCase = true) } ), - INDEPENDENT(Comparator { p1: PasswordItem, p2: PasswordItem -> p1.name.compareTo(p2.name, ignoreCase = true) }), + INDEPENDENT( + Comparator { p1: PasswordItem, p2: PasswordItem -> + p1.name.compareTo(p2.name, ignoreCase = true) + } + ), RECENTLY_USED( Comparator { p1: PasswordItem, p2: PasswordItem -> - val recentHistory = Application.instance.getSharedPreferences("recent_password_history", Context.MODE_PRIVATE) + val recentHistory = + Application.instance.getSharedPreferences("recent_password_history", Context.MODE_PRIVATE) val timeP1 = recentHistory.getString(p1.file.absolutePath.base64()) val timeP2 = recentHistory.getString(p2.file.absolutePath.base64()) when { diff --git a/app/src/main/java/dev/msfjarvis/aps/util/totp/UriTotpFinder.kt b/app/src/main/java/dev/msfjarvis/aps/util/totp/UriTotpFinder.kt index 2e954804..fa8481a9 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/totp/UriTotpFinder.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/totp/UriTotpFinder.kt @@ -44,7 +44,8 @@ class UriTotpFinder @Inject constructor() : TotpFinder { override fun findAlgorithm(content: String): String { content.split("\n".toRegex()).forEach { line -> - if (line.startsWith(TOTP_FIELDS[0]) && Uri.parse(line).getQueryParameter("algorithm") != null) { + if (line.startsWith(TOTP_FIELDS[0]) && Uri.parse(line).getQueryParameter("algorithm") != null + ) { return Uri.parse(line).getQueryParameter("algorithm")!! } } diff --git a/app/src/main/java/dev/msfjarvis/aps/util/viewmodel/SearchableRepositoryViewModel.kt b/app/src/main/java/dev/msfjarvis/aps/util/viewmodel/SearchableRepositoryViewModel.kt index f0488537..7106dbe3 100644 --- a/app/src/main/java/dev/msfjarvis/aps/util/viewmodel/SearchableRepositoryViewModel.kt +++ b/app/src/main/java/dev/msfjarvis/aps/util/viewmodel/SearchableRepositoryViewModel.kt @@ -75,8 +75,14 @@ private fun PasswordItem.Companion.makeComparator( PasswordSortOrder.FILE_FIRST -> compareByDescending { it.type } PasswordSortOrder.RECENTLY_USED -> PasswordSortOrder.RECENTLY_USED.comparator } - .then(compareBy(nullsLast(CaseInsensitiveComparator)) { directoryStructure.getIdentifierFor(it.file) }) - .then(compareBy(nullsLast(CaseInsensitiveComparator)) { directoryStructure.getUsernameFor(it.file) }) + .then( + compareBy(nullsLast(CaseInsensitiveComparator)) { + directoryStructure.getIdentifierFor(it.file) + } + ) + .then( + compareBy(nullsLast(CaseInsensitiveComparator)) { directoryStructure.getUsernameFor(it.file) } + ) } val PasswordItem.stableId: String @@ -179,7 +185,8 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel .mapLatest { searchAction -> val listResultFlow = when (searchAction.searchMode) { - SearchMode.RecursivelyInSubdirectories -> listFilesRecursively(searchAction.baseDirectory) + SearchMode.RecursivelyInSubdirectories -> + listFilesRecursively(searchAction.baseDirectory) SearchMode.InCurrentDirectoryOnly -> listFiles(searchAction.baseDirectory) } val prefilteredResultFlow = @@ -188,9 +195,8 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel ListMode.DirectoriesOnly -> listResultFlow.filter { it.isDirectory } ListMode.AllEntries -> listResultFlow } - val filterModeToUse = if (searchAction.filter == "") FilterMode.NoFilter else searchAction.filterMode val passwordList = - when (filterModeToUse) { + when (if (searchAction.filter == "") FilterMode.NoFilter else searchAction.filterMode) { FilterMode.NoFilter -> { prefilteredResultFlow.map { it.toPasswordItem() }.toList().sortedWith(itemComparator) } @@ -201,7 +207,9 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel val regex = generateStrictDomainRegex(searchAction.filter) if (regex != null) { prefilteredResultFlow - .filter { absoluteFile -> regex.containsMatchIn(absoluteFile.relativeTo(root).path) } + .filter { absoluteFile -> + regex.containsMatchIn(absoluteFile.relativeTo(root).path) + } .map { it.toPasswordItem() } .toList() .sortedWith(itemComparator) @@ -218,7 +226,9 @@ class SearchableRepositoryViewModel(application: Application) : AndroidViewModel .filter { it.first > 0 } .toList() .sortedWith( - compareByDescending<Pair<Int, PasswordItem>> { it.first }.thenBy(itemComparator) { it.second } + compareByDescending<Pair<Int, PasswordItem>> { it.first }.thenBy(itemComparator) { + it.second + } ) .map { it.second } } @@ -387,7 +397,9 @@ open class SearchableRepositoryAdapter<T : RecyclerView.ViewHolder>( addObserver( object : SelectionTracker.SelectionObserver<String>() { override fun onSelectionChanged() { - this@SearchableRepositoryAdapter.onSelectionChangedListener?.invoke(requireSelectionTracker().selection) + this@SearchableRepositoryAdapter.onSelectionChangedListener?.invoke( + requireSelectionTracker().selection + ) } } ) @@ -395,15 +407,23 @@ open class SearchableRepositoryAdapter<T : RecyclerView.ViewHolder>( } private var onItemClickedListener: ((holder: T, item: PasswordItem) -> Unit)? = null - open fun onItemClicked(listener: (holder: T, item: PasswordItem) -> Unit): SearchableRepositoryAdapter<T> { - check(onItemClickedListener == null) { "Only a single listener can be registered for onItemClicked" } + open fun onItemClicked( + listener: (holder: T, item: PasswordItem) -> Unit + ): SearchableRepositoryAdapter<T> { + check(onItemClickedListener == null) { + "Only a single listener can be registered for onItemClicked" + } onItemClickedListener = listener return this } private var onSelectionChangedListener: ((selection: Selection<String>) -> Unit)? = null - open fun onSelectionChanged(listener: (selection: Selection<String>) -> Unit): SearchableRepositoryAdapter<T> { - check(onSelectionChangedListener == null) { "Only a single listener can be registered for onSelectionChanged" } + open fun onSelectionChanged( + listener: (selection: Selection<String>) -> Unit + ): SearchableRepositoryAdapter<T> { + check(onSelectionChangedListener == null) { + "Only a single listener can be registered for onSelectionChanged" + } onSelectionChangedListener = listener return this } |
