Add option to automatically sync repository on app launch (#1137)

* Add option to automatically sync repository on app launch

Signed-off-by: Aditya Wasan <adityawasan55@gmail.com>

* Pull repo if user is not authenticated

Signed-off-by: Aditya Wasan <adityawasan55@gmail.com>

* Address review comments

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>

* Hijack incoming intent rather than copying it

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>

* Initialize password repository before using it

Signed-off-by: Aditya Wasan <adityawasan55@gmail.com>

Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
Aditya Wasan
2020-10-15 20:46:39 +05:30
committed by GitHub
parent a025ecf073
commit 92f1aab25d
7 changed files with 119 additions and 14 deletions

View File

@@ -42,8 +42,7 @@
<activity <activity
android:name=".LaunchActivity" android:name=".LaunchActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/app_name" android:label="@string/app_name">
android:theme="@style/NoBackgroundTheme">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />

View File

@@ -4,20 +4,34 @@
*/ */
package com.zeapo.pwdstore package com.zeapo.pwdstore
import android.content.ComponentName
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit import androidx.core.content.edit
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.github.michaelbull.result.fold
import com.zeapo.pwdstore.crypto.DecryptActivity import com.zeapo.pwdstore.crypto.DecryptActivity
import com.zeapo.pwdstore.databinding.ActivityLaunchBinding
import com.zeapo.pwdstore.git.BaseGitActivity
import com.zeapo.pwdstore.git.config.AuthMode
import com.zeapo.pwdstore.git.config.GitSettings
import com.zeapo.pwdstore.utils.BiometricAuthenticator import com.zeapo.pwdstore.utils.BiometricAuthenticator
import com.zeapo.pwdstore.utils.PasswordRepository
import com.zeapo.pwdstore.utils.PreferenceKeys import com.zeapo.pwdstore.utils.PreferenceKeys
import com.zeapo.pwdstore.utils.sharedPrefs import com.zeapo.pwdstore.utils.sharedPrefs
import com.zeapo.pwdstore.utils.viewBinding
import kotlinx.coroutines.launch
class LaunchActivity : AppCompatActivity() { class LaunchActivity : BaseGitActivity() {
private val binding by viewBinding(ActivityLaunchBinding::inflate)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(binding.root)
supportActionBar?.hide()
val prefs = sharedPrefs val prefs = sharedPrefs
if (prefs.getBoolean(PreferenceKeys.BIOMETRIC_AUTH, false)) { if (prefs.getBoolean(PreferenceKeys.BIOMETRIC_AUTH, false)) {
BiometricAuthenticator.authenticate(this) { BiometricAuthenticator.authenticate(this) {
@@ -40,18 +54,38 @@ class LaunchActivity : AppCompatActivity() {
} }
private fun startTargetActivity(noAuth: Boolean) { private fun startTargetActivity(noAuth: Boolean) {
val intentToStart = if (intent.action == ACTION_DECRYPT_PASS) if (intent.action == ACTION_DECRYPT_PASS) {
Intent(this, DecryptActivity::class.java).apply { intent.component = ComponentName(this, DecryptActivity::class.java)
putExtra("NAME", intent.getStringExtra("NAME")) startPasswordStoreActivity(intent, noAuth)
putExtra("FILE_PATH", intent.getStringExtra("FILE_PATH")) } else {
putExtra("REPO_PATH", intent.getStringExtra("REPO_PATH")) val intent = Intent(this, PasswordStore::class.java)
putExtra("LAST_CHANGED_TIMESTAMP", intent.getLongExtra("LAST_CHANGED_TIMESTAMP", 0L)) val repo = PasswordRepository.initialize()
// if repo is null, let PasswordStore handle it.
if (repo != null &&
!GitSettings.url.isNullOrEmpty() &&
sharedPrefs.getBoolean(PreferenceKeys.SYNC_ON_LAUNCH, false)) {
binding.progressBar.isVisible = true
binding.sync.isVisible = true
runGitOperation { startPasswordStoreActivity(intent, noAuth) }
} else {
startPasswordStoreActivity(intent, noAuth)
} }
else }
Intent(this, PasswordStore::class.java) }
startActivity(intentToStart)
Handler().postDelayed({ finish() }, if (noAuth) 0L else 500L) private fun startPasswordStoreActivity(intent: Intent, noAuth: Boolean) {
Handler().postDelayed({
startActivity(intent)
finish()
}, if (noAuth) 500L else 0L)
}
private fun runGitOperation(onCompletion: () -> Unit) = lifecycleScope.launch {
val gitOp = if (GitSettings.authMode == AuthMode.None) GitOp.PULL else GitOp.SYNC
launchGitOperation(gitOp).fold(
success = { onCompletion.invoke() },
failure = { promptOnErrorHandler(it) { onCompletion.invoke() } },
)
} }
companion object { companion object {

View File

@@ -46,6 +46,7 @@ import com.zeapo.pwdstore.autofill.AutofillPreferenceActivity
import com.zeapo.pwdstore.crypto.BasePgpActivity import com.zeapo.pwdstore.crypto.BasePgpActivity
import com.zeapo.pwdstore.git.GitConfigActivity import com.zeapo.pwdstore.git.GitConfigActivity
import com.zeapo.pwdstore.git.GitServerConfigActivity import com.zeapo.pwdstore.git.GitServerConfigActivity
import com.zeapo.pwdstore.git.config.GitSettings
import com.zeapo.pwdstore.git.sshj.SshKey import com.zeapo.pwdstore.git.sshj.SshKey
import com.zeapo.pwdstore.pwgenxkpwd.XkpwdDictionary import com.zeapo.pwdstore.pwgenxkpwd.XkpwdDictionary
import com.zeapo.pwdstore.sshkeygen.ShowSshKeyFragment import com.zeapo.pwdstore.sshkeygen.ShowSshKeyFragment
@@ -424,6 +425,8 @@ class UserPreference : AppCompatActivity() {
true true
} }
findPreference<CheckBoxPreference>(PreferenceKeys.SYNC_ON_LAUNCH)?.isVisible = !GitSettings.url.isNullOrEmpty()
val prefCustomXkpwdDictionary = findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT) val prefCustomXkpwdDictionary = findPreference<Preference>(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
prefCustomXkpwdDictionary?.onPreferenceClickListener = ClickListener { prefCustomXkpwdDictionary?.onPreferenceClickListener = ClickListener {
prefsActivity.storeCustomDictionaryPath() prefsActivity.storeCustomDictionaryPath()

View File

@@ -77,6 +77,7 @@ object PreferenceKeys {
const val SSH_OPENKEYSTORE_CLEAR_KEY_ID = "ssh_openkeystore_clear_keyid" const val SSH_OPENKEYSTORE_CLEAR_KEY_ID = "ssh_openkeystore_clear_keyid"
const val SSH_OPENKEYSTORE_KEYID = "ssh_openkeystore_keyid" const val SSH_OPENKEYSTORE_KEYID = "ssh_openkeystore_keyid"
const val SSH_SEE_KEY = "ssh_see_key" const val SSH_SEE_KEY = "ssh_see_key"
const val SYNC_ON_LAUNCH = "sync_on_launch"
@Deprecated("To be used only in Migrations.kt") @Deprecated("To be used only in Migrations.kt")
const val USE_GENERATED_KEY = "use_generated_key" const val USE_GENERATED_KEY = "use_generated_key"

View File

@@ -0,0 +1,59 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorPrimary"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/app_icon"
android:layout_width="100dp"
android:layout_height="100dp"
android:contentDescription="@string/app_icon_hint"
android:src="@mipmap/ic_launcher"
android:transitionName="transition_first_app_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"
android:text="@string/app_name"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
android:textColor="@color/color_control_normal"
android:textStyle="bold"
android:transitionName="transition_first_run_app_name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/app_icon" />
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.85" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/sync"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/syncing"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/color_control_normal"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/progress_bar" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -407,6 +407,9 @@
<!-- SSH port validation --> <!-- SSH port validation -->
<string name="ssh_scheme_needed_title">Potentially incorrect URL</string> <string name="ssh_scheme_needed_title">Potentially incorrect URL</string>
<string name="ssh_scheme_needed_message">It appears that your URL contains a custom port, but does not specify the ssh:// scheme.\nThis can cause the port to be considered a part of your path. Press OK here to fix the URL.</string> <string name="ssh_scheme_needed_message">It appears that your URL contains a custom port, but does not specify the ssh:// scheme.\nThis can cause the port to be considered a part of your path. Press OK here to fix the URL.</string>
<string name="sync_on_launch_title">Sync on launch</string>
<string name="sync_on_launch_summary">Sync passwords when application is launched</string>
<string name="syncing">Syncing…</string>
<!-- Proxy configuration activity --> <!-- Proxy configuration activity -->
<string name="proxy_hostname">Proxy hostname</string> <string name="proxy_hostname">Proxy hostname</string>

View File

@@ -138,6 +138,12 @@
app:key="biometric_auth" app:key="biometric_auth"
app:summary="@string/biometric_auth_summary" app:summary="@string/biometric_auth_summary"
app:title="@string/biometric_auth_title" /> app:title="@string/biometric_auth_title" />
<CheckBoxPreference
app:defaultValue="false"
app:key="sync_on_launch"
app:persistent="true"
app:summary="@string/sync_on_launch_summary"
app:title="@string/sync_on_launch_title" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory app:title="@string/pref_category_title_passwords"> <PreferenceCategory app:title="@string/pref_category_title_passwords">
<EditTextPreference <EditTextPreference