Skip to content

Commit 000b258

Browse files
authored
Merge pull request #133 from Kit/revoke-remove-tokens-uninstall
Revoke and Remove Tokens on Uninstall
2 parents 7f2facb + 4538844 commit 000b258

5 files changed

Lines changed: 232 additions & 0 deletions

File tree

.github/workflows/tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ jobs:
5959
'EndToEnd/forms',
6060
'EndToEnd/general',
6161
'EndToEnd/recommendations',
62+
'EndToEnd/uninstall',
6263
'Integration'
6364
]
6465

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
namespace Tests\EndToEnd;
4+
5+
use Tests\Support\EndToEndTester;
6+
7+
/**
8+
* Tests Plugin uninstallation.
9+
*
10+
* @since 1.9.2
11+
*/
12+
class UninstallCest
13+
{
14+
/**
15+
* Test that the Plugin's access and refresh tokens are revoked, and all v4 and v3
16+
* API credentials are removed from the Plugin's settings when the Plugin is deleted.
17+
*
18+
* @since 1.9.2
19+
*
20+
* @param EndToEndTester $I Tester.
21+
*/
22+
public function testPluginDeletionRevokesAndRemovesTokens(EndToEndTester $I)
23+
{
24+
// Activate this Plugin.
25+
$I->activateConvertKitPlugin($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->setupWPFormsIntegration(
50+
$I,
51+
accessToken: $tokens['access_token'],
52+
refreshToken: $tokens['refresh_token'],
53+
apiKey: $_ENV['CONVERTKIT_API_KEY'],
54+
apiSecret: $_ENV['CONVERTKIT_API_SECRET']
55+
);
56+
57+
// Deactivate the Plugin.
58+
$I->deactivateConvertKitPlugin($I);
59+
60+
// Delete the Plugin.
61+
$I->deleteKitPlugin($I);
62+
63+
// Confirm the credentials have been removed from the Plugin's settings.
64+
$I->wait(3);
65+
$settings = $I->grabOptionFromDatabase('wpforms_providers');
66+
$connection = reset($settings['convertkit']);
67+
$I->assertEmpty($connection['access_token']);
68+
$I->assertEmpty($connection['refresh_token']);
69+
$I->assertEmpty($connection['api_key']);
70+
$I->assertEmpty($connection['api_secret']);
71+
72+
// Confirm attempting to use the revoked access token no longer works.
73+
$result = wp_remote_get(
74+
'https://api.kit.com/v4/account',
75+
[
76+
'headers' => [
77+
'Authorization' => 'Bearer ' . $tokens['access_token'],
78+
],
79+
]
80+
);
81+
$data = json_decode(wp_remote_retrieve_body($result), true);
82+
$I->assertArrayHasKey( 'errors', $data );
83+
$I->assertEquals( 'The access token was revoked', $data['errors'][0] );
84+
85+
// Confirm attempting to use the revoked refresh token no longer works.
86+
$result = wp_remote_post(
87+
'https://api.kit.com/v4/oauth/token',
88+
[
89+
'headers' => [
90+
'Authorization' => 'Bearer ' . $tokens['access_token'],
91+
],
92+
'body' => [
93+
'client_id' => $_ENV['CONVERTKIT_OAUTH_CLIENT_ID'],
94+
'grant_type' => 'refresh_token',
95+
'refresh_token' => $tokens['refresh_token'],
96+
],
97+
]
98+
);
99+
$data = json_decode(wp_remote_retrieve_body($result), true);
100+
$I->assertArrayHasKey( 'error', $data );
101+
$I->assertEquals( 'invalid_grant', $data['error'] );
102+
}
103+
}

tests/Support/Helper/Plugin.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ public function deactivateConvertKitPlugin($I)
3535
$I->deactivateThirdPartyPlugin($I, 'integrate-convertkit-wpforms');
3636
}
3737

38+
/**
39+
* Helper method to delete the Kit Plugin.
40+
*
41+
* @since 1.9.2
42+
*
43+
* @param EndToEndTester $I EndToEndTester.
44+
*/
45+
public function deleteKitPlugin($I)
46+
{
47+
$I->deleteThirdPartyPlugin($I, 'integrate-convertkit-wpforms');
48+
}
49+
3850
/**
3951
* Helper method to determine that the order of the Form resources in the given
4052
* select element are in the expected alphabetical order.

tests/Support/Helper/ThirdPartyPlugin.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,39 @@ public function deactivateThirdPartyPlugin($I, $name)
7474
$I->waitForElementVisible('table.plugins tr[data-slug=' . $name . '].inactive');
7575
}
7676

77+
/**
78+
* Helper method to delete a third party Plugin, checking
79+
* it deleted and no errors were output.
80+
*
81+
* @since 1.9.2
82+
*
83+
* @param EndToEndTester $I EndToEnd Tester.
84+
* @param string $name Plugin Slug.
85+
*/
86+
public function deleteThirdPartyPlugin($I, $name)
87+
{
88+
// Login as the Administrator, if we're not already logged in.
89+
if ( ! $this->amLoggedInAsAdmin($I) ) {
90+
$this->doLoginAsAdmin($I);
91+
}
92+
93+
// Go to the Plugins screen in the WordPress Administration interface.
94+
$I->amOnPluginsPage();
95+
96+
// Wait for the Plugins page to load.
97+
$I->waitForElementVisible('body.plugins-php');
98+
99+
// Delete the Plugin.
100+
$I->waitForElementVisible('a#delete-' . $name);
101+
$I->click('a#delete-' . $name);
102+
103+
// Click the confirmation dialog.
104+
$I->acceptPopup();
105+
106+
// Wait for the Plugin to be marked as deleted.
107+
$I->waitForElementNotVisible('table.plugins tr.deleted[data-slug=' . $name . ']');
108+
}
109+
77110
/**
78111
* Helper method to check if the Administrator is logged in.
79112
*

uninstall.php

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
/**
3+
* Uninstall routine. Runs when the Plugin is deleted
4+
* at Plugins > Delete.
5+
*
6+
* @package CKWC
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 providers.
20+
$providers = get_option( 'wpforms_providers' );
21+
22+
// Bail if no providers exist.
23+
if ( ! $providers ) {
24+
return;
25+
}
26+
27+
// Bail if no Kit connections exist.
28+
if ( ! array_key_exists( 'convertkit', $providers ) ) {
29+
return;
30+
}
31+
32+
// Iterate through each connection, revoking the tokens.
33+
foreach ( $providers['convertkit'] as $account_id => $connection ) {
34+
// Revoke Access Token.
35+
if ( array_key_exists( 'access_token', $connection ) && ! empty( $connection['access_token'] ) ) {
36+
wp_remote_post(
37+
'https://api.kit.com/v4/oauth/revoke',
38+
array(
39+
'headers' => array(
40+
'Accept' => 'application/json',
41+
'Content-Type' => 'application/json',
42+
),
43+
'body' => wp_json_encode(
44+
array(
45+
'client_id' => 'L0kyADsB3WP5zO5MvUpXQU64gIntQg9BBAIme17r_7A',
46+
'token' => $connection['access_token'],
47+
)
48+
),
49+
'timeout' => 5,
50+
)
51+
);
52+
}
53+
54+
// Revoke Refresh Token.
55+
if ( array_key_exists( 'refresh_token', $connection ) && ! empty( $connection['refresh_token'] ) ) {
56+
wp_remote_post(
57+
'https://api.kit.com/v4/oauth/revoke',
58+
array(
59+
'headers' => array(
60+
'Accept' => 'application/json',
61+
'Content-Type' => 'application/json',
62+
),
63+
'body' => wp_json_encode(
64+
array(
65+
'client_id' => 'L0kyADsB3WP5zO5MvUpXQU64gIntQg9BBAIme17r_7A',
66+
'token' => $connection['refresh_token'],
67+
)
68+
),
69+
'timeout' => 5,
70+
)
71+
);
72+
}
73+
74+
// Remove credentials from settings.
75+
$providers['convertkit'][ $account_id ]['access_token'] = '';
76+
$providers['convertkit'][ $account_id ]['refresh_token'] = '';
77+
$providers['convertkit'][ $account_id ]['token_expires'] = '';
78+
$providers['convertkit'][ $account_id ]['api_key'] = '';
79+
$providers['convertkit'][ $account_id ]['api_secret'] = '';
80+
}
81+
82+
// Save settings.
83+
update_option( 'wpforms_providers', $providers );

0 commit comments

Comments
 (0)