docs: describe the repair path's per-account gate

The XML doc on AccountSecurity.RepairMigratedPasswords still described the
superseded single-switch design: it presented the flag as the only control
and never mentioned Account.RepairPasswordTag, so an operator reading only
that comment would enable the flag, watch nothing get repaired, and conclude
the feature was broken. Its cost rationale was overstated too -- the second
verify now runs only for tagged accounts, not on every failed login, so the
flag alone does not widen the credential-stuffing surface.

Rewrite it to say what the code does: master switch, tag independently
required, set from the admin gump and cleared on a successful repair, and
only ever on an account whose owner has reported the lockout -- because the
repair cannot tell a mis-migrated hash from a password that merely begins
with the username.

Cross-reference the two by cref in both directions so either comment leads
to the other. Comment-only; no behaviour change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kamron Batman 2026-08-07 17:40:37 -07:00
parent ccfbc1878a
commit da0d993186
2 changed files with 13 additions and 6 deletions

View file

@ -392,7 +392,8 @@ public partial class Account : IAccount, IComparable<Account>
/// reported being locked out, and never on one that can still log in: the repair cannot tell a
/// mis-migrated hash from a password that merely begins with the username, so marking a working
/// account risks rewriting its credential down to whatever was submitted. Cleared automatically
/// once a repair succeeds.
/// once a repair succeeds. Necessary but not sufficient: the shard-wide
/// <see cref="AccountSecurity.RepairMigratedPasswords"/> switch must be on as well.
/// </summary>
public const string RepairPasswordTag = "RepairMigratedPassword";

View file

@ -36,11 +36,17 @@ public static class AccountSecurity
public static PasswordProtectionAlgorithm CurrentAlgorithm { get; set; }
/// <summary>
/// Enables a one-time repair for accounts whose password was corrupted by the pre-fix
/// SetPassword, which hashed username + password but tagged it with an algorithm whose phrase
/// rule omits the username. Off by default: the repair costs a second verify on every FAILED
/// login, and failed logins are the credential-stuffing surface. Turn it on for a migration
/// window, then off again.
/// Shard-wide master switch for the one-time repair of accounts whose password was corrupted by
/// the pre-fix SetPassword, which stored the credential under the wrong family's phrase rule.
/// This flag alone repairs nothing: an account is only repaired when it *also* carries the
/// <see cref="Account.RepairPasswordTag"/> tag, which an operator adds from the admin gump
/// (Account Details -> Tags -> Add Tag) and which is cleared automatically once the repair
/// succeeds. Tag only an account whose owner has actually reported being locked out, never one
/// that can still log in: the repair cannot distinguish a mis-migrated hash from a password that
/// merely begins with the username, so tagging a working account risks rewriting its credential
/// down to whatever was submitted. Off by default because the repair costs a second verify on a
/// failed login -- for tagged accounts only, so the credential-stuffing surface is unaffected by
/// the flag on its own. Turn it on for a migration window, then off again.
/// </summary>
public static bool RepairMigratedPasswords { get; set; }