Problem/Motivation
If you have used this module to store passwords prior to 10.2.0 and use the passwords in anyway, e.g. by comparing with a value submitted in a form, or passing the unencrypted value to an API then a change introduced here https://git.drupalcode.org/project/drupal/-/commit/be46dafb302ad16eeab76... will break your code.
This is due to an additional parameter being added to the list being unset that causes the password to now be encrypted three times while all existing passwords saved before 10.2.0 have only been encrypted twice.
This does highlight the fact that I think the code in \Drupal\password_field\Plugin\Field\FieldType\PasswordField::__unset is not the correct way this code should be working. Setting the value using the unset magic method cannot possibly the correct way a module should be integrating with the Drupal code? The password should only be being encrypted once but because the field type is using the __unset method it is accidentally encrypting it twice prior to 10.2 and now three times in 10.2+.
Steps to reproduce
Install this module on any Drupal pre 10.2.0 and create lots of entities with a password. Add a custom module with a password field in a form that validates against the password stored in the entities (or integrate with a third part API to validate the password against). As long as you decrypt the value provided in the entity using password_field_encrypt_decrypt TWICE then the password will match.
Update Drupal to 10.2.0 and update an existing entity with a new password and your existing code will no longer work because the password has now accidentally been encrypted three times due to this core code in \Drupal\Core\Field\WidgetBase::extractFormValues trying to unset the _actions parameter as well:
// Put delta mapping in $form_state, so that flagErrors() can use it.
$field_state = static::getWidgetState($form['#parents'], $field_name, $form_state);
foreach ($items as $delta => $item) {
$field_state['original_deltas'][$delta] = $item->_original_delta ?? $delta;
unset($item->_original_delta, $item->_weight, $item->_actions);
}
See https://git.drupalcode.org/project/drupal/-/blob/11.x/core/lib/Drupal/Co...
Proposed resolution
Instead of using the __unset() magic method, use the preSave() method as the core \Drupal\Core\Field\Plugin\Field\FieldType\PasswordItem does.
/**
* {@inheritdoc}
*/
public function preSave() {
if (!empty($this->value)) {
$this->value = password_field_encrypt_decrypt('encrypt', $this->value);
}
}
However to maintain backwards compatibility the password_field_encrypt_decrypt
method must now double encrypt itself. I have checked an old D9.5.x site and that double encrypts but I don't know how far that behaviour goes back in time. I'm assuming anyone who then used this module has already written code to double decrypt.
Remaining tasks
The password field could be rewritten to extend the core Password field - just overriding the preSave method?