Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete user meta on plugin uninstall #637

Merged
merged 16 commits into from
Sep 19, 2024
Merged

Delete user meta on plugin uninstall #637

merged 16 commits into from
Sep 19, 2024

Conversation

kasparsd
Copy link
Collaborator

What?

Fixes #630.

Why?

Delete all used user meta keys and options during plugin uninstall as expected.

How?

  1. Register an uninstall hook for the plugin.

  2. During uninstall, collect all meta keys and options used by two-factor providers through a known class helper. Delete them by looping through each user (a performance concern on larger sites).

Consider using a direct database query to purge the user meta by keys to avoid looping through every user on larger sites.

Testing Instructions

  1. Setup the plugin with a few users and two-factor methods enabled for several users.
  2. Uninstall the plugin (in addition to deactivating).
  3. Activate the plugin again and confirm that no settings for providers have been preserved.

Screenshots or screencast

Changelog Entry

Added: register an uninstall hook for the plugin to delete all user meta data when the plugin is completely uninstalled.

class-two-factor-core.php Outdated Show resolved Hide resolved
*/
public static function get_providers() {
public static function get_providers_registered() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introducing dedicated methods for retrieving:

  1. all registered two-factor providers and their files.
  2. all registered two-factor providers and their classes without instantiating them (re-used by uninstall logic).
  3. all enabled providers (a subset of registered) and their classes instantiated (used as before).

*
* @return array
*/
public static function get_providers() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now much shorter as it can now get the class names for all enabled providers from the helpers.

*
* @return array
*/
public static function uninstall_user_meta_keys() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the two methods that providers can report their user meta key usage.

Copy link
Member

@dd32 dd32 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General direction WFM.

See comment on the related ticket about deleting meta values by mid instead for performance.

}

foreach ( $user_meta_keys as $meta_key ) {
delete_metadata( 'user', null, $meta_key, null, true );
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WP core uses this for deleting all post meta delete_post_meta_by_key() by key so we can re-use it as well.

@kasparsd kasparsd self-assigned this Sep 18, 2024
@kasparsd
Copy link
Collaborator Author

It is fun to test this locally -- it purges the whole plugin directory along with all git history. I even tried to create another symlinked plugin instances hoping that WP would only delete the symlink but it still took everything 😅

@kasparsd kasparsd merged commit 6a95e7f into master Sep 19, 2024
48 checks passed
@kasparsd kasparsd deleted the 630-fix-uninstall branch September 19, 2024 07:38
@kasparsd kasparsd mentioned this pull request Sep 19, 2024
@jeffpaul jeffpaul added this to the 0.10.0 milestone Sep 19, 2024
@vbondzio
Copy link

Hi Folks,

What would be considered sufficient DB cleanup in previous releases, just:

DELETE FROM wp_whatever_usermeta WHERE meta_key LIKE "_two_factor%";

?

This is also applicable for re-installations of the plugin (<0.10.0), for example in the completely hypothetical situation in which you accidentally reset your auth device without backing up the secrets and realize that your rarely opened 2FA recovery password manager DB had a racy sync at some point in the past. So if the only way in is deleting the plugin dir manually, then removing and re-installing, it would leave you in a spot in which you couldn't re-create a new secret (or even reuse the same) as you couldn't revalidate for the existing users. Completely hypothetical of course.

Cheers,

Valentin

* @param array $providers A key-value array where the key is the class name, and
* the value is the path to the file containing the class.
*/
$providers = apply_filters( 'two_factor_providers', $providers );
$additional_providers = apply_filters( 'two_factor_providers', $providers );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kasparsd Using the same existing filter seems wrong here. Shouldn't this be a new filter so you only get the additional providers?
Right now the filter is called twice in get_providers(), see

$providers = self::get_providers_registered();
/**
* Filter the supplied providers.
*
* This lets third-parties either remove providers (such as Email), or
* add their own providers (such as text message or Clef).
*
* @param array $providers A key-value array where the key is the class name, and
* the value is the path to the file containing the class.
*/
$providers = apply_filters( 'two_factor_providers', $providers );
.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kasparsd This still seems wrong to me and is now released. Why running the filter twice?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ocean90 Sorry for missing your comment here. I'll create a patch to address this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a pull request that removes the duplicate #651.

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.

Uninstallation Not Deleting Plugin Data
5 participants