mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-16 16:45:07 +00:00
27c289a4d6
Two accounts reach the same reset with opposite needs, and it treated both as "write a hash and hope". A provider-created account is told, on the Connected accounts screen, to "set a password first, then disconnect Google" -- and doing it changed nothing, because nothing ever set auth_source back to Local. AccountConversion is the only writer, and that is an administrator. So the screen went on asking for something that had already been done, and the person could not release their last provider without help. AuthSource states the rule that closes this: `social` means the account came into existence without anybody choosing a password, and, in as many words, "a social account may later set a real password". A reset by emailed token is where somebody does. The screen's has_local_password prop is literally auth_source === Local, so the write is what completes the sentence it prints. A directory account is the opposite case and gets the opposite answer. isDirectoryAccount() means the local hash is not consulted at all, so the reset reported success and left the person with a password that cannot sign them in -- including when the directory it points at is gone, which is exactly when somebody reaches for a reset. It is refused now, with the reason, and nothing about the account moves: taking one off its directory is an administrator's decision through AccountConversion, not a side effect of a reset. The refusal sits where the token has already been validated, not where the link is asked for. That endpoint answers "A reset link will be sent if the account exists" to everybody on purpose, and refusing there would tell a stranger both that an address is an account and how it signs in. Throwing before the write also leaves the token unspent, since PasswordBroker deletes it after the callback returns.