Skip to content

fix(autofill): align file path intent extra with BasePGPActivity - #195

Merged
pando85 merged 1 commit into
mainfrom
fix/autofill-decrypt-file-path
Sep 29, 2026
Merged

pando85 merged 1 commit into
mainfrom
fix/autofill-decrypt-file-path

Conversation

@pando85

@pando85 pando85 commented Sep 29, 2026

Copy link
Copy Markdown
Owner

Problem

Selecting a Password Store entry from the Android autofill UI in a browser (reproduced in Firefox)
crashed the app 100% of the time:

FATAL EXCEPTION: main
Process: app.passwordstore.pando85, PID: 13938
java.lang.IllegalArgumentException: FILE_PATH is missing
	at app.passwordstore.ui.crypto.BasePGPActivity.getFullPath
	at app.passwordstore.ui.crypto.BasePGPActivity.requireDecryptionKeysExist
	at app.passwordstore.ui.crypto.BasePGPActivity.requireKeysExist
	at app.passwordstore.ui.autofill.AutofillDecryptActivity.onStart

Root cause

AutofillDecryptActivity declared its own private constant

private const val EXTRA_FILE_PATH = "app.passwordstore.autofill.oreo.EXTRA_FILE_PATH"

and used it both to build its intents and to read the extra in onStart(). Its base class
BasePGPActivity however resolves fullPath from a different key:

val fullPath by unsafeLazy {
  requireNotNull(intent.getStringExtra(EXTRA_FILE_PATH)) { "${EXTRA_FILE_PATH} is missing" }
}

where BasePGPActivity.EXTRA_FILE_PATH == "FILE_PATH".

The mismatch was latent until a8bfc66 ("fix: recover nested GPG scope during key selection")
made requireDecryptionKeysExist() call resolveGpgIdScope(repoRoot, File(fullPath), subDir). That
was the first time fullPath was dereferenced on the autofill path, turning a silent inconsistency
into a hard crash on every autofill decrypt.

Fix

Delete the local constant and use BasePGPActivity.EXTRA_FILE_PATH at all three call sites
(onStart, makeDecryptFileIntent, makeDecryptFileIntentSender). This matches the convention
already used by every other component that talks to a BasePGPActivity subclass — DecryptActivity,
PassSecretsMapUnlockActivity, LaunchActivity, AutofillSaveActivity, PasswordStore,
PasswordItem. AutofillDecryptActivity was the sole outlier.

This fixes the root cause rather than papering over it: filePath and the base fullPath now read
the same extra, so the gpg-id scope is resolved against the real entry path.

Why not the upstream approach

Upstream avoids the crash by giving fullPath a fallback to the repository root:

intent.getStringExtra(EXTRA_FILE_PATH)
  ?: PasswordRepository.getRepositoryDirectory().absolutePath

That silently resolves the gpg-id scope against the repo root instead of the actual entry, which
would pick the wrong key for entries in nested .gpg-id scopes. Bridging the real path is correct.

Safety / regression review

  • The literal "app.passwordstore.autofill.oreo.EXTRA_FILE_PATH" appeared in exactly one file — no
    AndroidManifest.xml entry, test, deep link, or keep rule depends on it.
  • AutofillDecryptActivity is exported="false", and all three intent construction sites go through
    its own companion factories (AutofillFilterView, Api26AutofillResponseBuilder,
    Api30AutofillResponseBuilder). No external component can send this intent.
  • Verified BasePGPActivity.repoPath (EXTRA_REPO_PATH) is not dereferenced anywhere on the
    autofill decrypt path, so the crash does not merely move to the next missing extra.
  • The missing-extra case still degrades gracefully through the existing logcat(ERROR) + finish()
    guard in onStart() — no crash.
  • makeDecryptFileIntent applies putExtras(forwardedExtras) before putExtra(EXTRA_FILE_PATH, …),
    so a framework-supplied extra can never shadow the path.

Testing

  • Added AutofillDecryptActivityTest (Robolectric) asserting makeDecryptFileIntent carries the
    file path under BasePGPActivity.EXTRA_FILE_PATH. This fails against the old code.
  • On-device reproduction on a physical handset (Nothing, 3A281JEHN02185), app
    app.passwordstore.pando85 v1.25.1: crash reproduced and captured from logcat before the fix.
  • Full local CI equivalent green:
    spotlessCheck, assembleDebug, test -PslimTests, lint.

Changelog

Added an entry under [Unreleased] → Fixed.

AutofillDecryptActivity declared its own private EXTRA_FILE_PATH constant
("app.passwordstore.autofill.oreo.EXTRA_FILE_PATH") while its base class
BasePGPActivity reads the file path from the "FILE_PATH" extra. The mismatch
was latent until requireDecryptionKeysExist() began resolving the gpg-id scope
from fullPath (a8bfc66), which made every autofill decrypt crash with
IllegalArgumentException: FILE_PATH is missing.

Drop the local constant and use BasePGPActivity.EXTRA_FILE_PATH at all three
call sites, matching the convention already used by every other component in
the codebase. The missing-extra path still degrades gracefully via the
existing logcat(ERROR) + finish() guard in onStart().

Add a Robolectric test pinning the intent extra key contract so the mismatch
cannot silently return.
@pando85
pando85 merged commit 8f85e81 into main Sep 29, 2026
5 checks passed
@pando85
pando85 deleted the fix/autofill-decrypt-file-path branch September 29, 2026 07:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant