Allow re-encrypting attributes when app uses previous keys #1049
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
In #1033 the compare method is introduced, which is really nice! However, as Laravel now thinks the value is equal, it's impossible to "re-encrypt" the attributes without changing the actual value.
Issue
Say you have a model that uses one of the casts provided by this package and have set it up to encrypt that data. Afterwards, you rotate the app key and set the app previous keys. Laravel handles decrypting the value using your new or old key, whichever works. Now you want to get rid of the previous key, maybe it's leaked, and have all data encrypted using your new key. With the "native" encrypted casts provided by Laravel, the value is re-encrypted using the new key and marked as dirty on update (see https://github.com/laravel/framework/blob/959fac8/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php#L2284-L2285 for details). So if you want to re-encrypt all data, you can just loop over all models, set the attribute to trigger a re-encrypt, and save them. However, since version #1033 introduced the compare function, Laravel thinks the values are equal and it doesn't mark the attribute as dirty and doesn't save the re-encrypted value.
Solution
By implementing the same logic as Laravel, i.e. marking the attribute as dirty when there are previous encryption keys, we restore the ability to re-encrypt all data.