Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
3f9cda2
fix(passkeys): use WorkManager for passkey auto-sync to survive activ…
Jul 30, 2026
a749d02
fix(passkeys): add commit message and reduce duplication in PasskeySy…
Jul 30, 2026
4d3213d
fix(passkeys): cast Key to PrivateKey in PasskeySyncWorker
Jul 30, 2026
9b80a1a
serialize shared git operations
pando85 Jul 31, 2026
39605fd
add reusable headless passkey git sync engine
pando85 Jul 31, 2026
98d36d2
make passkey sync durable and non-cancelling
pando85 Jul 31, 2026
67b40fa
serialize foreground and background git access
pando85 Jul 31, 2026
339030a
reopen repository for durable passkey sync
pando85 Jul 31, 2026
759c8eb
test git operation serialization
pando85 Jul 31, 2026
b40b425
format passkey sync worker
pando85 Jul 31, 2026
bc2dee0
format headless passkey git sync engine
pando85 Jul 31, 2026
deb0dae
apply spotless formatting to passkey sync worker
pando85 Jul 31, 2026
1112caa
apply spotless formatting to serialized git operations
pando85 Jul 31, 2026
65ca9ce
fix coroutine lint in coordinator test
pando85 Jul 31, 2026
90c1a93
feat(passkeys): carry changed Git paths through sync result
pando85 Jul 31, 2026
cdfe86f
feat(passkeys): add remote refresh contract
pando85 Jul 31, 2026
8b4e7d8
feat(passkeys): support pull-only remote refresh with changed paths
pando85 Jul 31, 2026
a139c46
perf(passkeys): incrementally reconcile index after Git pull
pando85 Jul 31, 2026
e276b15
feat(passkeys): refresh remote once on credential lookup miss
pando85 Jul 31, 2026
ff73f8b
feat(passkeys): expose headless remote refresh to credential provider
pando85 Jul 31, 2026
baa6008
fix(passkeys): merge credential provider companion constants
pando85 Jul 31, 2026
7b3924e
test(passkeys): cover changed-path sync classification
pando85 Jul 31, 2026
5b62e81
fix(passkeys): bound miss refresh latency and initialize cold repository
pando85 Jul 31, 2026
58199e7
fix(passkeys): do not suppress first remote refresh after boot
pando85 Jul 31, 2026
992e0c9
style(passkeys): format remote refresher provider
pando85 Jul 31, 2026
1f51be5
style(passkeys): format incremental index reconciliation
pando85 Jul 31, 2026
dbba696
style(passkeys): format miss-recovery coroutine
pando85 Jul 31, 2026
5e52dd8
perf(passkeys): reconcile changed passkey files directly
pando85 Jul 31, 2026
de40f96
fix(passkeys): handle unavailable source versions during reconciliation
pando85 Jul 31, 2026
8315770
style(passkeys): wrap credential entry loader signature
pando85 Jul 31, 2026
9bfa69e
test(passkeys): verify direct incremental Git index reconciliation
pando85 Jul 31, 2026
b1bfdaa
style(passkeys): format incremental Git reconciliation tests
pando85 Jul 31, 2026
d6a1507
fix(passkeys): avoid coroutine cancel extension conflict
pando85 Jul 31, 2026
910fa68
fix(passkeys): coalesce only concurrent remote refreshes
pando85 Jul 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@
package app.passwordstore.passkeys

import androidx.annotation.RequiresApi
import app.passwordstore.Application
import app.passwordstore.passkeys.crypto.PasskeyCryptoHandler
import app.passwordstore.passkeys.provider.PasskeyCredentialProviderService
import app.passwordstore.passkeys.storage.PasskeyRemoteRefresher
import app.passwordstore.passkeys.storage.PasskeyStorage
import app.passwordstore.util.extensions.sharedPrefs
import app.passwordstore.util.settings.PreferenceKeys
import dagger.hilt.EntryPoint
import dagger.hilt.InstallIn
import dagger.hilt.android.EntryPointAccessors
Expand All @@ -29,12 +33,22 @@ class AppPasskeyCredentialProviderService : PasskeyCredentialProviderService() {
override val providerActivity: Class<out android.app.Activity>
get() = AppPasskeyProviderActivity::class.java

override val remoteRefresher: PasskeyRemoteRefresher?
get() =
if (Application.instance.sharedPrefs.getBoolean(PreferenceKeys.PASSKEY_AUTO_GIT_SYNC, true)) {
entryPoint.passkeyGitSyncEngine()
} else {
null
}

@EntryPoint
@InstallIn(SingletonComponent::class)
interface PasskeysEntryPoint {

fun passkeyStorage(): PasskeyStorage

fun passkeyCryptoHandler(): PasskeyCryptoHandler

fun passkeyGitSyncEngine(): PasskeyGitSyncEngine
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import app.passwordstore.passkeys.provider.PasskeyAuthenticator
import app.passwordstore.passkeys.provider.PasskeyCredentialProviderService
import app.passwordstore.passkeys.provider.PasskeyProviderUtils
import app.passwordstore.passkeys.provider.caller.WebAuthnCallerVerifier
import app.passwordstore.passkeys.storage.GitSyncResult
import app.passwordstore.passkeys.storage.MissingRecipientKeyException
import app.passwordstore.passkeys.storage.PasskeyRepositoryState
import app.passwordstore.passkeys.storage.PasskeyStorage
Expand All @@ -44,7 +43,6 @@ import app.passwordstore.passkeys.storage.SignatureCounterPolicy
import app.passwordstore.passkeys.storage.SignatureCounterTransaction
import app.passwordstore.passkeys.storage.SourceVersionResult
import app.passwordstore.ui.git.base.BaseGitActivity
import app.passwordstore.ui.git.base.BaseGitActivity.GitOp
import app.passwordstore.ui.pgp.PGPKeyListActivity
import app.passwordstore.util.extensions.sharedPrefs
import app.passwordstore.util.settings.PreferenceKeys
Expand Down Expand Up @@ -80,30 +78,7 @@ class AppPasskeyProviderActivity : BaseGitActivity() {
if (!sharedPrefs.getBoolean(PreferenceKeys.PASSKEY_AUTO_GIT_SYNC, true)) return
if (gitSettings.url == null) return
if (PasswordRepository.repository == null) return
lifecycleScope.launch(dispatcherProvider.io()) {
try {
val oldHead = generationProvider.currentGitHead()
launchGitOperation(GitOp.SYNC)
.fold(
success = {
val newHead = generationProvider.currentGitHead()
val syncResult =
GitSyncResult(
oldHead = oldHead,
newHead = newHead,
worktreeChanged = oldHead != newHead,
conflicts = emptyList(),
)
passkeyRepositoryState.onGitSyncCompleted(syncResult)
generationProvider.bumpWorktreeGeneration()
logcat { "Passkey auto-sync completed" }
},
failure = { logcat(LogPriority.WARN) { "Passkey auto-sync failed: $it" } },
)
} catch (e: Exception) {
logcat(LogPriority.WARN) { "Passkey auto-sync crashed: $e" }
}
}
PasskeySyncWorker.enqueue(this)
}

@RequiresApi(34)
Expand Down
Loading