Skip to content

fix: imported accounts are subject to the password lifetime - #884

Merged
blaipr merged 1 commit into
mainfrom
fix/imported-accounts-are-subject-to-the-password-lifetime
Aug 26, 2026
Merged

fix: imported accounts are subject to the password lifetime#884
blaipr merged 1 commit into
mainfrom
fix/imported-accounts-are-subject-to-the-password-lifetime

Conversation

@blaipr

@blaipr blaipr commented Aug 26, 2026

Copy link
Copy Markdown
Member

Every door that creates an account asks the preset service to clamp passDateChange to
the policy's lifetime — the web form does it, and so do the API's create and edit-pass.
The importers do not: ImportBase::addAccount() goes straight to
AccountService::create(), which applies the permission and privacy presets but has never
applied the password ones. So a fixed policy saying passwords expire after ninety days
said nothing at all about the several thousand accounts that arrived through a CSV, a
KeePass file or a sysPass export — which is exactly the population most likely to be
carrying old credentials.

The clamp is applied on import now, for all three importers, since they share this method.

checkPasswordPreset() — the one that validates length and character classes — is
deliberately not applied, and this is the judgement in the change rather than the code.
An import is a migration of credentials that already exist somewhere else. Refusing the
ones that predate the policy would mean not being able to migrate at all, and the import
runs in a single transaction, so one weak password would take the whole file with it. The
policy still bites the moment the account is next edited, and the lifetime clamp is what
makes somebody get there rather than waiting for it to be noticed.

The preset service reaches ImportBase through ImportHelper, which is how it already gets
the account, category, client, tag and config services.

Checked by dropping the clamp: the new test fails, asserting on the stored DTO rather than
on the clamp having been called.

The test needed the clamp stub to consult a per-test value rather than being re-stubbed in
the test itself — the first stub registered is the one that answers, so a per-test override
of a setUp stub silently does nothing. That is the second time that has caught me today.

Every door that creates an account asks the preset service to clamp `passDateChange` to
the policy's lifetime — the web form does it, and so do the API's create and edit-pass.
The importers do not: `ImportBase::addAccount()` goes straight to
`AccountService::create()`, which applies the permission and privacy presets but has never
applied the password ones. So a fixed policy saying passwords expire after ninety days
said nothing at all about the several thousand accounts that arrived through a CSV, a
KeePass file or a sysPass export — which is exactly the population most likely to be
carrying old credentials.

The clamp is applied on import now, for all three importers, since they share this method.

`checkPasswordPreset()` — the one that validates length and character classes — is
deliberately *not* applied, and this is the judgement in the change rather than the code.
An import is a migration of credentials that already exist somewhere else. Refusing the
ones that predate the policy would mean not being able to migrate at all, and the import
runs in a single transaction, so one weak password would take the whole file with it. The
policy still bites the moment the account is next edited, and the lifetime clamp is what
makes somebody get there rather than waiting for it to be noticed.

The preset service reaches ImportBase through ImportHelper, which is how it already gets
the account, category, client, tag and config services.

Checked by dropping the clamp: the new test fails, asserting on the stored DTO rather than
on the clamp having been called.

The test needed the clamp stub to consult a per-test value rather than being re-stubbed in
the test itself — the first stub registered is the one that answers, so a per-test override
of a setUp stub silently does nothing. That is the second time that has caught me today.
@blaipr
blaipr merged commit 6480140 into main Aug 26, 2026
8 checks passed
@blaipr
blaipr deleted the fix/imported-accounts-are-subject-to-the-password-lifetime branch August 26, 2026 19:51
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