From 0656ee5fda52d775922b03ad2b759e5197695e4d Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 31 Oct 2019 23:29:43 +0200 Subject: [PATCH 1/5] initial 1.0 migration class --- includes/Core/Util/Migration_1_0_0.php | 120 +++++++++++++++++++++++++ includes/Plugin.php | 1 + 2 files changed, 121 insertions(+) create mode 100644 includes/Core/Util/Migration_1_0_0.php diff --git a/includes/Core/Util/Migration_1_0_0.php b/includes/Core/Util/Migration_1_0_0.php new file mode 100644 index 00000000000..3d3c77bc13a --- /dev/null +++ b/includes/Core/Util/Migration_1_0_0.php @@ -0,0 +1,120 @@ +context = $context; + $this->options = new Options( $context ); + } + + /** + * Registers hooks. + */ + public function register() { + add_action( 'admin_init', array( $this, 'migrate' ) ); + } + + /** + * Migrates the DB. + */ + public function migrate() { + $db_version = $this->options->get( 'googlesitekit_db_version' ); + + if ( ! $db_version || version_compare( $db_version, self::DB_VERSION, '<' ) ) { + $this->migrate_install(); + + $this->options->set( 'googlesitekit_db_version', self::DB_VERSION ); + } + } + + /** + * Migrates old credentials and disconnects users. + */ + private function migrate_install() { + $credentials = ( new Encrypted_Options( $this->options ) )->get( Credentials::OPTION ); + + // Credentials can be filtered in so we must also check if there is a saved option present. + if ( isset( $credentials['oauth2_client_id'] ) && strpos( $credentials['oauth2_client_id'], '.apps.sitekit.withgoogle.com' ) ) { + $this->options->delete( Credentials::OPTION ); + $this->options->set( Beta_Migration::OPTION_IS_PRE_PROXY_INSTALL, 1 ); + + $this->disconnect_users(); + + wp_cache_flush(); + } + } + + /** + * Disconnects authenticated users. + */ + private function disconnect_users() { + global $wpdb; + + $user_options = new User_Options( $this->context ); + $authentication = new Authentication( $this->context, $this->options, $user_options ); + + $user_ids = $wpdb->get_col( + $wpdb->prepare( + " + SELECT user_id + FROM {$wpdb->usermeta} + WHERE meta_key IN ( %s, %s ) + ", + OAuth_Client::OPTION_ACCESS_TOKEN, + $wpdb->get_blog_prefix() . OAuth_Client::OPTION_ACCESS_TOKEN + ) + ); + + foreach ( $user_ids as $user_id ) { + $user_options->switch_user( (int) $user_id ); + $authentication->disconnect(); + } + } +} diff --git a/includes/Plugin.php b/includes/Plugin.php index 814808abd6f..c6e22b0e3fe 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -148,6 +148,7 @@ function( $username, $user ) use ( $user_options ) { ( new Core\Util\Activation( $this->context, $options, $assets ) )->register(); ( new Core\Util\Beta_Migration( $this->context ) )->register(); + ( new Core\Util\Migration_1_0_0( $this->context ) )->register(); ( new Core\Util\Uninstallation( $reset ) )->register(); if ( defined( 'WP_DEBUG' ) && true === WP_DEBUG ) { From 9ac1a86641b9c0f2cfeb7593b241fea2dab5e0ac Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Thu, 31 Oct 2019 23:48:56 +0200 Subject: [PATCH 2/5] add Migration_1_0_0Test --- .../Core/Util/Migration_1_0_0Test.php | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 tests/phpunit/integration/Core/Util/Migration_1_0_0Test.php diff --git a/tests/phpunit/integration/Core/Util/Migration_1_0_0Test.php b/tests/phpunit/integration/Core/Util/Migration_1_0_0Test.php new file mode 100644 index 00000000000..bb987d67acf --- /dev/null +++ b/tests/phpunit/integration/Core/Util/Migration_1_0_0Test.php @@ -0,0 +1,139 @@ +register(); + + $this->assertTrue( has_action( 'admin_init' ) ); + } + + public function test_migrate() { + $context = new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ); + $options = new Options( $context ); + $credentials = new Credentials( $options ); + $migration = new Migration_1_0_0( $context ); + + // Upgrade will update the DB version if run. + $this->delete_db_version(); + + $migration->migrate(); + + $this->assertEquals( Migration_1_0_0::DB_VERSION, $this->get_db_version() ); + + // The upgrade will NOT delete old GCP credentials if present. + $this->delete_db_version(); + $this->set_gcp_credentials(); + $this->assertTrue( $credentials->has() ); + + $migration->migrate(); + + $this->assertTrue( $credentials->has() ); + $this->assertEquals( Migration_1_0_0::DB_VERSION, $this->get_db_version() ); + + // The upgrade WILL delete proxy credentials if present. + $this->delete_db_version(); + $this->set_proxy_credentials(); + $this->assertTrue( $credentials->has() ); + + $migration->migrate(); + + $this->assertFalse( $credentials->has() ); + $this->assertEquals( Migration_1_0_0::DB_VERSION, $this->get_db_version() ); + + // The upgrade will not disconnect any user if GCP credentials are present. + $this->delete_db_version(); + $this->set_gcp_credentials(); + + $users_with_tokens = array( + $this->create_user_with_access_token(), + $this->create_user_with_access_token(), + $this->create_user_with_access_token(), + ); + $users_without = array( + $this->factory()->user->create(), + $this->factory()->user->create(), + $this->factory()->user->create(), + ); + + $migration->migrate(); + + foreach ( $users_with_tokens as $user_with_token ) { + $this->assertUserHasAccessToken( $user_with_token ); + } + + // The upgrade will disconnect any user with an auth token if proxy credentials are present. + $this->delete_db_version(); + $this->set_proxy_credentials(); + + $migration->migrate(); + + foreach ( $users_with_tokens as $user_who_had_token ) { + $this->assertUserNotHasAccessToken( $user_who_had_token ); + } + foreach ( $users_without as $user_without ) { + $this->assertUserNotHasAccessToken( $user_without ); + } + } + + private function assertUserHasAccessToken( $user_id ) { + $this->assertNotEmpty( get_user_option( OAuth_Client::OPTION_ACCESS_TOKEN, $user_id ) ); + } + + private function assertUserNotHasAccessToken( $user_id ) { + $this->assertEmpty( get_user_option( OAuth_Client::OPTION_ACCESS_TOKEN, $user_id ) ); + } + + private function create_user_with_access_token() { + $user_id = $this->factory()->user->create(); + update_user_option( $user_id, OAuth_Client::OPTION_ACCESS_TOKEN, "test-access-token-$user_id" ); + + return $user_id; + } + + private function get_db_version() { + return ( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) )->get( 'googlesitekit_db_version' ); + } + + private function delete_db_version() { + ( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) )->delete( 'googlesitekit_db_version' ); + } + + private function delete_credentials() { + ( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) )->delete( Credentials::OPTION ); + } + + private function set_gcp_credentials() { + ( new Credentials( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) ) )->set( array( + 'oauth2_client_id' => 'test-client-id.apps.googleusercontent.com', + 'oauth2_client_secret' => 'test-client-secret', + ) ); + } + + private function set_proxy_credentials() { + ( new Credentials( new Options( new Context( GOOGLESITEKIT_PLUGIN_MAIN_FILE ) ) ) )->set( array( + 'oauth2_client_id' => 'test-site-id.apps.sitekit.withgoogle.com', + 'oauth2_client_secret' => 'test-site-secret', + ) ); + } +} From bd3cb37130a4ce134879304ce5b477f3a23f1dd7 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Fri, 1 Nov 2019 00:06:34 +0200 Subject: [PATCH 3/5] refactor direct db query to use WP_User_Query --- includes/Core/Util/Migration_1_0_0.php | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/includes/Core/Util/Migration_1_0_0.php b/includes/Core/Util/Migration_1_0_0.php index 3d3c77bc13a..cae33d6e291 100644 --- a/includes/Core/Util/Migration_1_0_0.php +++ b/includes/Core/Util/Migration_1_0_0.php @@ -100,17 +100,15 @@ private function disconnect_users() { $user_options = new User_Options( $this->context ); $authentication = new Authentication( $this->context, $this->options, $user_options ); - $user_ids = $wpdb->get_col( - $wpdb->prepare( - " - SELECT user_id - FROM {$wpdb->usermeta} - WHERE meta_key IN ( %s, %s ) - ", - OAuth_Client::OPTION_ACCESS_TOKEN, - $wpdb->get_blog_prefix() . OAuth_Client::OPTION_ACCESS_TOKEN + // User option keys are prefixed in single site and multisite when not in network mode. + $key_prefix = $this->context->is_network_mode() ? '' : $wpdb->get_blog_prefix(); + $user_ids = ( new \WP_User_Query( + array( + 'fields' => 'id', + 'meta_key' => $key_prefix . OAuth_Client::OPTION_ACCESS_TOKEN, + 'compare' => 'EXISTS', ) - ); + ) )->get_results(); foreach ( $user_ids as $user_id ) { $user_options->switch_user( (int) $user_id ); From fb86da66661f5f0556611b2cb2b746c33accd128 Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Fri, 1 Nov 2019 00:07:02 +0200 Subject: [PATCH 4/5] Simplify constructor name in docblock --- includes/Core/Util/Migration_1_0_0.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Core/Util/Migration_1_0_0.php b/includes/Core/Util/Migration_1_0_0.php index cae33d6e291..1ed209ba5d8 100644 --- a/includes/Core/Util/Migration_1_0_0.php +++ b/includes/Core/Util/Migration_1_0_0.php @@ -45,7 +45,7 @@ class Migration_1_0_0 { protected $options; /** - * Migration_1_0_0 constructor. + * Constructor. * * @param Context $context Plugin context instance. */ From 22c40478f44b11b82369cffcadbda8a17752a9fe Mon Sep 17 00:00:00 2001 From: Evan Mattson Date: Fri, 1 Nov 2019 00:11:26 +0200 Subject: [PATCH 5/5] docblocks - update class block - add @since on methods --- includes/Core/Util/Migration_1_0_0.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/includes/Core/Util/Migration_1_0_0.php b/includes/Core/Util/Migration_1_0_0.php index 1ed209ba5d8..8a1c59c6e10 100644 --- a/includes/Core/Util/Migration_1_0_0.php +++ b/includes/Core/Util/Migration_1_0_0.php @@ -21,7 +21,9 @@ /** * Class Migration_1_0_0 * - * @package Google\Site_Kit\Core\Util + * @since 1.0.0 + * @access private + * @ignore */ class Migration_1_0_0 { @@ -47,6 +49,8 @@ class Migration_1_0_0 { /** * Constructor. * + * @since 1.0.0 + * * @param Context $context Plugin context instance. */ public function __construct( Context $context ) { @@ -56,6 +60,8 @@ public function __construct( Context $context ) { /** * Registers hooks. + * + * @since 1.0.0 */ public function register() { add_action( 'admin_init', array( $this, 'migrate' ) ); @@ -63,6 +69,8 @@ public function register() { /** * Migrates the DB. + * + * @since 1.0.0 */ public function migrate() { $db_version = $this->options->get( 'googlesitekit_db_version' ); @@ -76,6 +84,8 @@ public function migrate() { /** * Migrates old credentials and disconnects users. + * + * @since 1.0.0 */ private function migrate_install() { $credentials = ( new Encrypted_Options( $this->options ) )->get( Credentials::OPTION ); @@ -93,6 +103,8 @@ private function migrate_install() { /** * Disconnects authenticated users. + * + * @since 1.0.0 */ private function disconnect_users() { global $wpdb;