Skip to content

Commit 0caef45

Browse files
authored
Merge pull request #1066 from Kit/remove-revoke-tokens-uninstall
Revoke and Remove Tokens on Uninstall
2 parents dcee91c + 941e458 commit 0caef45

6 files changed

Lines changed: 232 additions & 0 deletions

File tree

.github/workflows/tests.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ jobs:
6969
'EndToEnd/forms/general',
7070
'EndToEnd/forms/post-types',
7171
'EndToEnd/general/other',
72+
'EndToEnd/general/uninstall',
7273
'EndToEnd/general/plugin-screens',
7374
'EndToEnd/integrations/divi-builder',
7475
'EndToEnd/integrations/divi-theme',
@@ -187,7 +188,10 @@ jobs:
187188
188189
# DISALLOW_FILE_MODS = true is required to disable the block directory's "Available to Install" suggestions, which trips up
189190
# tests that search and wait for block results.
191+
# We don't enable DISALLOW_FILE_MODS for the UninstallCest test, as tests will perform a Plugin deletion
192+
# which requires DISALLOW_FILE_MODS to not be true.
190193
- name: Enable DISALLOW_FILE_MODS
194+
if: ${{ matrix.test-groups != 'EndToEnd/general/uninstall' }}
191195
working-directory: ${{ env.ROOT_DIR }}
192196
run: |
193197
wp-cli config set DISALLOW_FILE_MODS true --raw

tests/EndToEnd/general/other/ActivateDeactivatePluginCest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,6 @@ public function testPluginActivationAndDeactivationWithOtherPlugins(EndToEndTest
5959
// Deactivate Plugins.
6060
$I->deactivateThirdPartyPlugin($I, 'convertkit-for-woocommerce');
6161
$I->deactivateKitPlugin($I);
62+
$I->resetKitPlugin($I);
6263
}
6364
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
namespace Tests\EndToEnd;
4+
5+
use Tests\Support\EndToEndTester;
6+
7+
/**
8+
* Tests Plugin uninstallation.
9+
*
10+
* @since 3.2.4
11+
*/
12+
class UninstallCest
13+
{
14+
/**
15+
* Test that the Plugin's access and refresh tokens are revoked, and all v4 and v4
16+
* API credentials are removed from the Plugin's settings when the Plugin is deleted.
17+
*
18+
* @since 3.2.4
19+
*
20+
* @param EndToEndTester $I Tester.
21+
*/
22+
public function testPluginDeletionRevokesAndRemovesTokens(EndToEndTester $I)
23+
{
24+
// Activate this Plugin.
25+
$I->activateKitPlugin($I);
26+
27+
// Generate an access token and refresh token by API key and secret.
28+
// We don't use the tokens from the environment, as revoking those
29+
// would result in later tests failing.
30+
$result = wp_remote_post(
31+
'https://api.kit.com/wordpress/accounts/oauth_access_token',
32+
[
33+
'headers' => [
34+
'Content-Type' => 'application/json',
35+
],
36+
'body' => wp_json_encode(
37+
[
38+
'api_key' => $_ENV['CONVERTKIT_API_KEY'],
39+
'api_secret' => $_ENV['CONVERTKIT_API_SECRET'],
40+
'client_id' => $_ENV['CONVERTKIT_OAUTH_CLIENT_ID'],
41+
'tenant_name' => wp_generate_password( 10, false ), // Random tenant name to produce a token for this request only.
42+
]
43+
),
44+
]
45+
);
46+
$tokens = json_decode(wp_remote_retrieve_body($result), true)['oauth'];
47+
48+
// Store the tokens and API keys in the Plugin's settings.
49+
$I->setupKitPlugin(
50+
$I,
51+
[
52+
'access_token' => $tokens['access_token'],
53+
'refresh_token' => $tokens['refresh_token'],
54+
'token_expires' => $tokens['expires_at'],
55+
'api_key' => $_ENV['CONVERTKIT_API_KEY'],
56+
'api_secret' => $_ENV['CONVERTKIT_API_SECRET'],
57+
]
58+
);
59+
60+
// Deactivate the Plugin.
61+
$I->deactivateKitPlugin($I);
62+
63+
// Delete the Plugin.
64+
$I->deleteKitPlugin($I);
65+
66+
// Confirm the credentials have been removed from the Plugin's settings.
67+
$I->wait(3);
68+
$settings = $I->grabOptionFromDatabase('_wp_convertkit_settings');
69+
$I->assertEmpty($settings['access_token']);
70+
$I->assertEmpty($settings['refresh_token']);
71+
$I->assertEmpty($settings['token_expires']);
72+
$I->assertEmpty($settings['api_key']);
73+
$I->assertEmpty($settings['api_secret']);
74+
75+
// Confirm attempting to use the revoked access token no longer works.
76+
$result = wp_remote_get(
77+
'https://api.kit.com/v4/account',
78+
[
79+
'headers' => [
80+
'Authorization' => 'Bearer ' . $tokens['access_token'],
81+
],
82+
]
83+
);
84+
$data = json_decode(wp_remote_retrieve_body($result), true);
85+
$I->assertArrayHasKey( 'errors', $data );
86+
$I->assertEquals( 'The access token was revoked', $data['errors'][0] );
87+
88+
// Confirm attempting to use the revoked refresh token no longer works.
89+
$result = wp_remote_post(
90+
'https://api.kit.com/v4/oauth/token',
91+
[
92+
'headers' => [
93+
'Authorization' => 'Bearer ' . $tokens['access_token'],
94+
],
95+
'body' => [
96+
'client_id' => $_ENV['CONVERTKIT_OAUTH_CLIENT_ID'],
97+
'grant_type' => 'refresh_token',
98+
'refresh_token' => $tokens['refresh_token'],
99+
],
100+
]
101+
);
102+
$data = json_decode(wp_remote_retrieve_body($result), true);
103+
$I->assertArrayHasKey( 'error', $data );
104+
$I->assertEquals( 'invalid_grant', $data['error'] );
105+
}
106+
}

tests/Support/Helper/KitPlugin.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ public function deactivateKitPlugin($I)
3838
$I->deactivateThirdPartyPlugin($I, 'convertkit');
3939
}
4040

41+
/**
42+
* Helper method to delete the Kit Plugin, checking
43+
* it deleted and no errors were output.
44+
*
45+
* @since 3.2.4
46+
*
47+
* @param EndToEndTester $I EndToEndTester.
48+
*/
49+
public function deleteKitPlugin($I)
50+
{
51+
$I->deleteThirdPartyPlugin($I, 'convertkit');
52+
}
53+
4154
/**
4255
* Helper method to programmatically setup the Plugin's settings, as if the
4356
* user configured the Plugin at `Settings > Kit`.

tests/Support/Helper/ThirdPartyPlugin.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,39 @@ public function deactivateThirdPartyPlugin($I, $name)
121121
}
122122
}
123123

124+
/**
125+
* Helper method to delete a third party Plugin, checking
126+
* it deleted and no errors were output.
127+
*
128+
* @since 3.2.4
129+
*
130+
* @param EndToEndTester $I EndToEnd Tester.
131+
* @param string $name Plugin Slug.
132+
*/
133+
public function deleteThirdPartyPlugin($I, $name)
134+
{
135+
// Login as the Administrator, if we're not already logged in.
136+
if ( ! $this->amLoggedInAsAdmin($I) ) {
137+
$this->doLoginAsAdmin($I);
138+
}
139+
140+
// Go to the Plugins screen in the WordPress Administration interface.
141+
$I->amOnPluginsPage();
142+
143+
// Wait for the Plugins page to load.
144+
$I->waitForElementVisible('body.plugins-php');
145+
146+
// Delete the Plugin.
147+
$I->waitForElementVisible('a#delete-' . $name);
148+
$I->click('a#delete-' . $name);
149+
150+
// Click the confirmation dialog.
151+
$I->acceptPopup();
152+
153+
// Wait for the Plugin to be marked as deleted.
154+
$I->waitForElementNotVisible('table.plugins tr.deleted[data-slug=' . $name . ']');
155+
}
156+
124157
/**
125158
* Helper method to check if the Administrator is logged in.
126159
*

uninstall.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
/**
3+
* Uninstall routine. Runs when the Plugin is deleted
4+
* at Plugins > Delete.
5+
*
6+
* @package ConvertKit
7+
* @author ConvertKit
8+
*/
9+
10+
// If uninstall.php is not called by WordPress, die.
11+
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
12+
die;
13+
}
14+
15+
// Only WordPress and PHP methods can be used. Plugin classes and methods
16+
// are not reliably available due to the Plugin being deactivated and going
17+
// through deletion now.
18+
19+
// Get settings.
20+
$settings = get_option( '_wp_convertkit_settings' );
21+
22+
// Bail if no settings exist.
23+
if ( ! $settings ) {
24+
return;
25+
}
26+
27+
// Revoke Access Token.
28+
if ( array_key_exists( 'access_token', $settings ) && ! empty( $settings['access_token'] ) ) {
29+
wp_remote_post(
30+
'https://api.kit.com/v4/oauth/revoke',
31+
array(
32+
'headers' => array(
33+
'Accept' => 'application/json',
34+
'Content-Type' => 'application/json',
35+
),
36+
'body' => wp_json_encode(
37+
array(
38+
'client_id' => 'HXZlOCj-K5r0ufuWCtyoyo3f688VmMAYSsKg1eGvw0Y',
39+
'token' => $settings['access_token'],
40+
)
41+
),
42+
'timeout' => 5,
43+
)
44+
);
45+
}
46+
47+
// Revoke Refresh Token.
48+
if ( array_key_exists( 'refresh_token', $settings ) && ! empty( $settings['refresh_token'] ) ) {
49+
wp_remote_post(
50+
'https://api.kit.com/v4/oauth/revoke',
51+
array(
52+
'headers' => array(
53+
'Accept' => 'application/json',
54+
'Content-Type' => 'application/json',
55+
),
56+
'body' => wp_json_encode(
57+
array(
58+
'client_id' => 'HXZlOCj-K5r0ufuWCtyoyo3f688VmMAYSsKg1eGvw0Y',
59+
'token' => $settings['refresh_token'],
60+
)
61+
),
62+
'timeout' => 5,
63+
)
64+
);
65+
}
66+
67+
// Remove credentials from settings.
68+
$settings['access_token'] = '';
69+
$settings['refresh_token'] = '';
70+
$settings['token_expires'] = '';
71+
$settings['api_key'] = '';
72+
$settings['api_secret'] = '';
73+
74+
// Save settings.
75+
update_option( '_wp_convertkit_settings', $settings );

0 commit comments

Comments
 (0)