Skip to content

Commit e0c3e69

Browse files
committed
refactor: Relocate Kit and Freemius classes to dedicated namespaces and extract credential validation logic
1 parent 980704b commit e0c3e69

10 files changed

Lines changed: 407 additions & 355 deletions

includes/admin/class-kit-oauth.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88

99
namespace WebberZone\FreemKit\Admin;
1010

11-
use WebberZone\FreemKit\Kit_API;
12-
use WebberZone\FreemKit\Kit_Audit_Log;
13-
use WebberZone\FreemKit\Kit_Settings;
11+
use WebberZone\FreemKit\Kit\Kit_API;
12+
use WebberZone\FreemKit\Kit\Kit_Audit_Log;
13+
use WebberZone\FreemKit\Kit\Kit_Settings;
1414
use WebberZone\FreemKit\Util\Hook_Registry;
1515

1616
/**
@@ -81,6 +81,7 @@ public function maybe_handle_requests(): void {
8181
$result = $api->get_access_token( $authorization_code );
8282

8383
if ( is_wp_error( $result ) ) {
84+
/* translators: %s: Error message */
8485
Kit_Audit_Log::add( 'oauth_connect_failed', array( 'error' => $result->get_error_message() ), 'warning' );
8586
Admin::add_notice( sprintf( esc_html__( 'Kit OAuth failed: %s', 'freemkit' ), $result->get_error_message() ), 'notice-error' );
8687
wp_safe_redirect( $this->get_settings_url() );

includes/admin/class-settings.php

Lines changed: 8 additions & 319 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
namespace WebberZone\FreemKit\Admin;
1111

1212
use WebberZone\FreemKit\Admin\Settings\Settings_API;
13+
use WebberZone\FreemKit\Freemius;
1314
use WebberZone\FreemKit\Options_API;
15+
use WebberZone\FreemKit\Kit\Kit_API;
1416

1517
// If this file is called directly, abort.
1618
if ( ! defined( 'WPINC' ) ) {
@@ -901,7 +903,7 @@ public function handle_kit_search() {
901903
$data = $this->get_kit_custom_fields( $query );
902904
break;
903905
case 'freemius_events':
904-
$data = self::get_freemius_events( $query );
906+
$data = Freemius::get_events( $query );
905907
break;
906908
default:
907909
$data = array();
@@ -973,7 +975,7 @@ public function ajax_test_kit_connection() {
973975
wp_send_json_error( (object) array( 'message' => esc_html__( 'You do not have permission to perform this action.', 'freemkit' ) ) );
974976
}
975977

976-
$api = new \WebberZone\FreemKit\Kit_API();
978+
$api = new Kit_API();
977979
$result = $api->get_account();
978980

979981
if ( is_wp_error( $result ) ) {
@@ -1153,143 +1155,7 @@ private function resolve_secret_key_for_validation( string $secret_key, array $s
11531155
* @return array<string,string>|\WP_Error
11541156
*/
11551157
private function validate_freemius_credentials( string $plugin_id, string $public_key, string $secret_key ) {
1156-
$resource_path = sprintf( '/v1/products/%s.json', rawurlencode( $plugin_id ) );
1157-
$url = 'https://api.freemius.com' . $resource_path;
1158-
$response = null;
1159-
1160-
// Attempt the request using FS authorization signatures.
1161-
foreach ( array( 'binary', 'hex' ) as $signature_mode ) {
1162-
$response = wp_remote_get(
1163-
$url,
1164-
array(
1165-
'timeout' => 15,
1166-
'headers' => $this->build_freemius_fs_headers( 'GET', $resource_path, '', $plugin_id, $public_key, $secret_key, $signature_mode ),
1167-
)
1168-
);
1169-
1170-
if ( is_wp_error( $response ) ) {
1171-
return new \WP_Error(
1172-
'freemius_request_error',
1173-
sprintf(
1174-
/* translators: %s: Error details. */
1175-
esc_html__( 'Could not reach Freemius to validate credentials: %s', 'freemkit' ),
1176-
$response->get_error_message()
1177-
)
1178-
);
1179-
}
1180-
1181-
$status_code = (int) wp_remote_retrieve_response_code( $response );
1182-
if ( $status_code >= 200 && $status_code < 300 ) {
1183-
break;
1184-
}
1185-
}
1186-
1187-
$status_code = (int) wp_remote_retrieve_response_code( $response );
1188-
$body = (string) wp_remote_retrieve_body( $response );
1189-
$data = json_decode( $body, true );
1190-
$product = ( is_array( $data ) && isset( $data['product'] ) && is_array( $data['product'] ) ) ? $data['product'] : ( is_array( $data ) ? $data : array() );
1191-
1192-
if ( $status_code < 200 || $status_code >= 300 ) {
1193-
$api_message = '';
1194-
if ( is_array( $data ) && isset( $data['error']['message'] ) && is_string( $data['error']['message'] ) ) {
1195-
$api_message = sanitize_text_field( $data['error']['message'] );
1196-
}
1197-
1198-
$message = $this->map_freemius_validation_error_message( $status_code, $api_message, $plugin_id );
1199-
1200-
return new \WP_Error(
1201-
'freemius_invalid_credentials',
1202-
$message,
1203-
array(
1204-
'status_code' => $status_code,
1205-
'api_message' => $api_message,
1206-
)
1207-
);
1208-
}
1209-
1210-
$returned_id = isset( $product['id'] ) ? (string) $product['id'] : '';
1211-
$name = isset( $product['title'] ) ? (string) $product['title'] : ( isset( $product['name'] ) ? (string) $product['name'] : __( 'this product', 'freemkit' ) );
1212-
1213-
if ( '' !== $returned_id && $returned_id !== $plugin_id ) {
1214-
return new \WP_Error( 'freemius_product_mismatch', esc_html__( 'Credentials are valid, but they do not match the entered Product ID.', 'freemkit' ) );
1215-
}
1216-
1217-
return array(
1218-
'id' => '' !== $returned_id ? $returned_id : $plugin_id,
1219-
'name' => sanitize_text_field( $name ),
1220-
);
1221-
}
1222-
1223-
/**
1224-
* Build Freemius FS authorization headers.
1225-
*
1226-
* @param string $method HTTP method.
1227-
* @param string $resource_path API resource path.
1228-
* @param string $body Request body.
1229-
* @param string $scope_entity_id Freemius scope entity ID (product ID).
1230-
* @param string $public_key Public key.
1231-
* @param string $secret_key Secret key.
1232-
* @param string $signature_mode Signature mode ('binary' or 'hex').
1233-
* @return array<string,string>
1234-
*/
1235-
private function build_freemius_fs_headers( string $method, string $resource_path, string $body, string $scope_entity_id, string $public_key, string $secret_key, string $signature_mode = 'binary' ): array {
1236-
$date = gmdate( 'D, d M Y H:i:s O' );
1237-
$content_type = 'application/json';
1238-
$md5 = '' === $body ? '' : md5( $body ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_md5
1239-
$string = strtoupper( $method ) . "\n" . $md5 . "\n" . $content_type . "\n" . $date . "\n" . $resource_path;
1240-
1241-
if ( 'hex' === $signature_mode ) {
1242-
$hmac = hash_hmac( 'sha256', $string, $secret_key );
1243-
} else {
1244-
$hmac = hash_hmac( 'sha256', $string, $secret_key, true );
1245-
}
1246-
1247-
$signature = rtrim( strtr( base64_encode( $hmac ), '+/', '-_' ), '=' ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
1248-
1249-
return array(
1250-
'Authorization' => sprintf( 'FS %s:%s:%s', $scope_entity_id, $public_key, $signature ),
1251-
'Content-Type' => $content_type,
1252-
'Accept' => 'application/json',
1253-
'Date' => $date,
1254-
);
1255-
}
1256-
1257-
/**
1258-
* Map Freemius API auth errors to clearer admin messages.
1259-
*
1260-
* @param int $status_code HTTP status code.
1261-
* @param string $api_message Raw Freemius error message.
1262-
* @param string $plugin_id Submitted product ID.
1263-
* @return string
1264-
*/
1265-
private function map_freemius_validation_error_message( int $status_code, string $api_message, string $plugin_id ): string {
1266-
$message_lc = strtolower( $api_message );
1267-
1268-
if ( false !== strpos( $message_lc, 'invalid authorization header' ) ) {
1269-
return sprintf(
1270-
/* translators: %s: Product ID. */
1271-
esc_html__( 'Could not validate Product ID %s. Re-check Product ID, Public Key, and Secret Key for this product.', 'freemkit' ),
1272-
$plugin_id
1273-
);
1274-
}
1275-
1276-
if ( false !== strpos( $message_lc, 'must use fs authorization' ) ) {
1277-
return esc_html__( 'Freemius rejected the authorization method for this request. Please verify your product credentials and try again.', 'freemkit' );
1278-
}
1279-
1280-
if ( 401 === $status_code || 403 === $status_code ) {
1281-
return sprintf(
1282-
/* translators: %s: Product ID. */
1283-
esc_html__( 'Access denied for Product ID %s. Confirm the keys belong to this exact product.', 'freemkit' ),
1284-
$plugin_id
1285-
);
1286-
}
1287-
1288-
if ( '' !== $api_message ) {
1289-
return $api_message;
1290-
}
1291-
1292-
return esc_html__( 'Freemius rejected the credentials. Please verify Product ID, public key, and secret key.', 'freemkit' );
1158+
return Freemius::validate_credentials( $plugin_id, $public_key, $secret_key );
12931159
}
12941160

12951161
/**
@@ -1306,7 +1172,7 @@ public static function get_kit_data( string $type, string $search = '' ) {
13061172
$items = get_transient( $transient_key );
13071173

13081174
if ( false === $items ) {
1309-
$api = new \WebberZone\FreemKit\Kit_API();
1175+
$api = new Kit_API();
13101176
$has = $api->validate_api_credentials();
13111177

13121178
if ( is_wp_error( $has ) ) {
@@ -1371,7 +1237,7 @@ function ( $item ) use ( $search ) {
13711237
*/
13721238
public static function get_localized_kit_data( string $type ): array {
13731239
if ( 'freemius_events' === $type ) {
1374-
return self::get_freemius_events();
1240+
return Freemius::get_events();
13751241
}
13761242

13771243
$data = self::get_kit_data( $type );
@@ -1385,184 +1251,7 @@ public static function get_localized_kit_data( string $type ): array {
13851251
* @return array<int,array<string,string>>
13861252
*/
13871253
public static function get_freemius_events( string $search = '' ): array {
1388-
$events = array(
1389-
'affiliate.approved',
1390-
'affiliate.blocked',
1391-
'affiliate.created',
1392-
'affiliate.deleted',
1393-
'affiliate.payout.pending',
1394-
'affiliate.paypal.updated',
1395-
'affiliate.rejected',
1396-
'affiliate.suspended',
1397-
'affiliate.unapproved',
1398-
'affiliate.updated',
1399-
'card.created',
1400-
'card.updated',
1401-
'cart.abandoned',
1402-
'install.installed',
1403-
'cart.completed',
1404-
'cart.created',
1405-
'cart.recovered',
1406-
'cart.recovery.deactivated',
1407-
'cart.recovery.email_1_sent',
1408-
'cart.recovery.email_2_sent',
1409-
'cart.recovery.email_3_sent',
1410-
'cart.recovery.reactivated',
1411-
'cart.recovery.subscribed',
1412-
'cart.recovery.unsubscribed',
1413-
'cart.updated',
1414-
'coupon.created',
1415-
'coupon.deleted',
1416-
'coupon.updated',
1417-
'email.clicked',
1418-
'email.opened',
1419-
'install.activated',
1420-
'install.deactivated',
1421-
'install.deleted',
1422-
'install.premium.activated',
1423-
'install.connected',
1424-
'install.disconnected',
1425-
'install.language.updated',
1426-
'install.plan.changed',
1427-
'install.plan.downgraded',
1428-
'install.platform.version.updated',
1429-
'install.premium.deactivated',
1430-
'install.programming_language.version.updated',
1431-
'install.sdk.version.updated',
1432-
'install.title.updated',
1433-
'install.trial.started',
1434-
'install.trial.extended',
1435-
'install.trial.cancelled',
1436-
'install.trial.expired',
1437-
'install.trial_expiring_notice.sent',
1438-
'install.trial.plan.updated',
1439-
'install.uninstalled',
1440-
'install.updated',
1441-
'install.url.updated',
1442-
'install.version.downgrade',
1443-
'install.version.upgraded',
1444-
'license.created',
1445-
'license.activated',
1446-
'license.updated',
1447-
'license.extended',
1448-
'license.shortened',
1449-
'license.expired',
1450-
'license.expired_notice.sent',
1451-
'license.cancelled',
1452-
'license.deactivated',
1453-
'license.deleted',
1454-
'license.ownership.changed',
1455-
'license.quota.changed',
1456-
'license.renewal_reminder.sent',
1457-
'license.trial_expiring_notice.sent',
1458-
'license.site.blacklisted',
1459-
'license.blacklisted_site.deleted',
1460-
'license.site.whitelisted',
1461-
'license.whitelisted_site.deleted',
1462-
'member.created',
1463-
'member.deleted',
1464-
'member.updated',
1465-
'plan.created',
1466-
'plan.deleted',
1467-
'subscription.created',
1468-
'subscription.cancelled',
1469-
'subscription.renewal_reminder.sent',
1470-
'subscription.renewal_reminder.opened',
1471-
'subscription.renewal.retry',
1472-
'subscription.renewal.failed',
1473-
'subscription.renewal.failed.last',
1474-
'subscription.renewal.failed_email.sent',
1475-
'subscription.renewals.discounted',
1476-
'payment.created',
1477-
'payment.refund',
1478-
'payment.dispute.created',
1479-
'payment.dispute.closed',
1480-
'payment.dispute.lost',
1481-
'payment.dispute.won',
1482-
'plan.lifetime.purchase',
1483-
'plan.updated',
1484-
'pricing.created',
1485-
'pricing.deleted',
1486-
'pricing.updated',
1487-
'review.created',
1488-
'review.deleted',
1489-
'review.requested',
1490-
'review.updated',
1491-
'store.created',
1492-
'store.dashboard_url.updated',
1493-
'store.plugin.added',
1494-
'store.plugin.removed',
1495-
'store.url.updated',
1496-
'user.beta_program.opted_in',
1497-
'user.beta_program.opted_out',
1498-
'user.billing.updated',
1499-
'user.billing.tax_id.updated',
1500-
'user.card.created',
1501-
'user.created',
1502-
'user.email.changed',
1503-
'user.email.verified',
1504-
'user.email_status.bounced',
1505-
'user.email_status.delivered',
1506-
'user.email_status.dropped',
1507-
'user.marketing.opted_in',
1508-
'user.marketing.opted_out',
1509-
'user.marketing.reset',
1510-
'user.name.changed',
1511-
'user.support.contacted',
1512-
'user.trial.started',
1513-
'webhook.created',
1514-
'webhook.deleted',
1515-
'webhook.updated',
1516-
'addon.free.downloaded',
1517-
'addon.premium.downloaded',
1518-
'install.extensions.opt_in',
1519-
'install.extensions.opt_out',
1520-
'install.ownership.candidate.confirmed',
1521-
'install.ownership.completed',
1522-
'install.ownership.initiated',
1523-
'install.ownership.owner.confirmed',
1524-
'install.site.opt_in',
1525-
'install.site.opt_out',
1526-
'install.user.opt_in',
1527-
'install.user.opt_out',
1528-
'plugin.free.downloaded',
1529-
'plugin.premium.downloaded',
1530-
'plugin.version.deleted',
1531-
'plugin.version.deployed',
1532-
'plugin.version.released',
1533-
'plugin.version.beta.released',
1534-
'plugin.version.release.suspended',
1535-
'plugin.version.updated',
1536-
'pricing.visit',
1537-
);
1538-
$events = array_values( array_unique( array_filter( $events ) ) );
1539-
$events = apply_filters( 'freemkit_freemius_events', $events );
1540-
$events = array_values( array_unique( array_filter( array_map( 'strval', (array) $events ) ) ) );
1541-
1542-
$items = array_map(
1543-
static function ( string $event ): array {
1544-
return array(
1545-
'id' => $event,
1546-
'name' => $event,
1547-
);
1548-
},
1549-
$events
1550-
);
1551-
1552-
if ( '' !== $search ) {
1553-
$query = strtolower( trim( $search ) );
1554-
$items = array_values(
1555-
array_filter(
1556-
$items,
1557-
static function ( array $item ) use ( $query ): bool {
1558-
$needle = strtolower( $item['id'] . ' ' . $item['name'] );
1559-
return false !== strpos( $needle, $query );
1560-
}
1561-
)
1562-
);
1563-
}
1564-
1565-
return $items;
1254+
return Freemius::get_events( $search );
15661255
}
15671256

15681257
/**

0 commit comments

Comments
 (0)