From 225dfebaef48b9925a05787e0230308f6502332c Mon Sep 17 00:00:00 2001 From: Vitalii Solovei Date: Fri, 5 Jun 2026 20:00:14 +0200 Subject: [PATCH 1/2] add logs (WP-1007) Co-Authored-By: Claude Sonnet 4.6 --- inc/Smartling/Bootstrap.php | 7 +++++-- inc/Smartling/Helpers/UiMessageHelper.php | 9 ++++++++- .../Services/ContentRelationsHandler.php | 14 +++++++++++-- .../WP/Controller/CheckStatusController.php | 7 ++++++- .../ConfigurationProfileFormController.php | 7 ++++++- .../Controller/ContentEditJobController.php | 12 ++++++----- .../InstantTranslationController.php | 14 +++++++++++-- .../Controller/LiveNotificationController.php | 7 ++++++- .../PostBasedWidgetControllerStd.php | 14 +++++++++++-- .../WP/Controller/TaxonomyLinksController.php | 7 ++++++- .../WP/Controller/TestRunController.php | 7 ++++++- .../WP/Controller/VisualConfiguratorPage.php | 20 +++++++++++++------ 12 files changed, 100 insertions(+), 25 deletions(-) diff --git a/inc/Smartling/Bootstrap.php b/inc/Smartling/Bootstrap.php index 7a0a32df..f4a3261b 100644 --- a/inc/Smartling/Bootstrap.php +++ b/inc/Smartling/Bootstrap.php @@ -181,10 +181,13 @@ private function initRoles(): void #[NoReturn] public function updateGlobalExpertSettings(): void { - check_ajax_referer('smartling_expert_global_settings', '_wpnonce'); + if (check_ajax_referer('smartling_expert_global_settings', '_wpnonce', false) === false) { + static::getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', 'smartling_expert_global_settings', get_current_user_id())); + wp_send_json(['error' => 'Invalid nonce'], 403); + } if (!current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_PROFILE_CAP)) { + static::getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_PROFILE_CAP)); wp_send_json(['error' => 'Insufficient permissions'], 403); - return; } $data = $_POST['params']; diff --git a/inc/Smartling/Helpers/UiMessageHelper.php b/inc/Smartling/Helpers/UiMessageHelper.php index f034d059..476dfccb 100644 --- a/inc/Smartling/Helpers/UiMessageHelper.php +++ b/inc/Smartling/Helpers/UiMessageHelper.php @@ -2,6 +2,8 @@ namespace Smartling\Helpers; +use Smartling\Bootstrap; + class UiMessageHelper { private const CACHE_KEY_PREFIX = 'smartling.ui.message.'; @@ -9,8 +11,13 @@ class UiMessageHelper public static function dismissMessage(): void { - check_ajax_referer(self::DISMISS_MESSAGE_ACTION, '_wpnonce'); + if (check_ajax_referer(self::DISMISS_MESSAGE_ACTION, '_wpnonce', false) === false) { + Bootstrap::getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', self::DISMISS_MESSAGE_ACTION, get_current_user_id())); + wp_send_json_error(['message' => 'Invalid nonce'], 403); + return; + } if (!current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_MENU_CAP)) { + Bootstrap::getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_MENU_CAP)); wp_send_json_error(['message' => 'Insufficient permissions'], 403); return; } diff --git a/inc/Smartling/Services/ContentRelationsHandler.php b/inc/Smartling/Services/ContentRelationsHandler.php index 43e3e124..62d8a935 100644 --- a/inc/Smartling/Services/ContentRelationsHandler.php +++ b/inc/Smartling/Services/ContentRelationsHandler.php @@ -81,8 +81,13 @@ public function register(): void */ public function createSubmissionsHandler(array $data = null): void { - $this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce'); + if ($this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', 'smartling_translation', get_current_user_id())); + $this->returnError('invalid.nonce', 'Invalid nonce', 403); + return; + } if (!$this->wpProxy->current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)); $this->returnError('permission.denied', 'Insufficient permissions', 403); return; } @@ -104,8 +109,13 @@ public function createSubmissionsHandler(array $data = null): void public function actionHandler(): void { - $this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce'); + if ($this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', 'smartling_translation', get_current_user_id())); + $this->returnError('invalid.nonce', 'Invalid nonce', 403); + return; + } if (!$this->wpProxy->current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)); $this->returnError('permission.denied', 'Insufficient permissions', 403); return; } diff --git a/inc/Smartling/WP/Controller/CheckStatusController.php b/inc/Smartling/WP/Controller/CheckStatusController.php index 905358ad..d31f6353 100644 --- a/inc/Smartling/WP/Controller/CheckStatusController.php +++ b/inc/Smartling/WP/Controller/CheckStatusController.php @@ -39,8 +39,13 @@ public function register(): void */ public function ajaxHandler() { - check_ajax_referer('smartling_check_status', '_wpnonce'); + if (check_ajax_referer('smartling_check_status', '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', 'smartling_check_status', get_current_user_id())); + wp_send_json(['error' => 'Invalid nonce'], 403); + return false; + } if (!current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)); wp_send_json(['error' => 'Insufficient permissions'], 403); return false; } diff --git a/inc/Smartling/WP/Controller/ConfigurationProfileFormController.php b/inc/Smartling/WP/Controller/ConfigurationProfileFormController.php index 37dea44d..81835595 100644 --- a/inc/Smartling/WP/Controller/ConfigurationProfileFormController.php +++ b/inc/Smartling/WP/Controller/ConfigurationProfileFormController.php @@ -50,8 +50,13 @@ public function register(): void public function initTestConnectionEndpoint(): void { - check_ajax_referer('smartling_test_connection', '_wpnonce'); + if (check_ajax_referer('smartling_test_connection', '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', 'smartling_test_connection', get_current_user_id())); + wp_send_json(['status' => 403, 'message' => 'Invalid nonce'], 403); + return; + } if (!current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_PROFILE_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_PROFILE_CAP)); wp_send_json(['status' => 403, 'message' => 'Insufficient permissions'], 403); return; } diff --git a/inc/Smartling/WP/Controller/ContentEditJobController.php b/inc/Smartling/WP/Controller/ContentEditJobController.php index 9927d6ef..0bdb2737 100644 --- a/inc/Smartling/WP/Controller/ContentEditJobController.php +++ b/inc/Smartling/WP/Controller/ContentEditJobController.php @@ -27,8 +27,6 @@ class ContentEditJobController extends WPAbstract implements WPHookInterface { public const SMARTLING_JOB_API_PROXY = 'smartling_job_api_proxy'; - private WordpressFunctionProxyHelper $wpProxy; - public function __construct( ApiWrapperInterface $api, LocalizationPluginProxyInterface $localizationPluginProxy, @@ -37,10 +35,9 @@ public function __construct( SiteHelper $siteHelper, SubmissionManager $submissionManager, Cache $cache, - WordpressFunctionProxyHelper $wpProxy, + private WordpressFunctionProxyHelper $wpProxy, ) { parent::__construct($api, $localizationPluginProxy, $pluginInfo, $settingsManager, $siteHelper, $submissionManager, $cache); - $this->wpProxy = $wpProxy; } /** * @var string @@ -87,8 +84,13 @@ public function setServedContentType($servedContentType) public function initJobApiProxy(): void { add_action('wp_ajax_' . self::SMARTLING_JOB_API_PROXY, function () { - $this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce'); + if ($this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', 'smartling_translation', get_current_user_id())); + $this->wpProxy->wp_send_json(['status' => 403, 'message' => 'Invalid nonce'], 403); + return; + } if (!$this->wpProxy->current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)); $this->wpProxy->wp_send_json(['status' => 403, 'message' => 'Insufficient permissions'], 403); return; } diff --git a/inc/Smartling/WP/Controller/InstantTranslationController.php b/inc/Smartling/WP/Controller/InstantTranslationController.php index 5fcaf0b0..56067f0b 100644 --- a/inc/Smartling/WP/Controller/InstantTranslationController.php +++ b/inc/Smartling/WP/Controller/InstantTranslationController.php @@ -37,9 +37,14 @@ public function register(): void public function handleRequestTranslation(): void { - $this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce'); + if ($this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', 'smartling_translation', get_current_user_id())); + $this->wpProxy->wp_send_json_error(['message' => 'Invalid nonce'], 403); + return; + } if (!$this->wpProxy->current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)); $this->wpProxy->wp_send_json_error(['message' => 'Insufficient permissions'], 403); return; } @@ -139,9 +144,14 @@ public function handleRequestTranslation(): void public function handlePollStatus(): void { - $this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce'); + if ($this->wpProxy->check_ajax_referer('smartling_translation', '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', 'smartling_translation', get_current_user_id())); + $this->wpProxy->wp_send_json_error(['message' => 'Invalid nonce'], 403); + return; + } if (!$this->wpProxy->current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)); $this->wpProxy->wp_send_json_error(['message' => 'Insufficient permissions'], 403); return; } diff --git a/inc/Smartling/WP/Controller/LiveNotificationController.php b/inc/Smartling/WP/Controller/LiveNotificationController.php index 76093d87..5eab570c 100644 --- a/inc/Smartling/WP/Controller/LiveNotificationController.php +++ b/inc/Smartling/WP/Controller/LiveNotificationController.php @@ -116,8 +116,13 @@ public function placeJsConfig(): void public function deleteNotificationAjaxHandler(): void { - check_ajax_referer(self::DELETE_NOTIFICATION_ACTION_NAME, '_wpnonce'); + if (check_ajax_referer(self::DELETE_NOTIFICATION_ACTION_NAME, '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', self::DELETE_NOTIFICATION_ACTION_NAME, get_current_user_id())); + wp_send_json(['code' => 'error', 'message' => 'Invalid nonce'], 403); + return; + } if (!current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)); wp_send_json(['code' => 'error', 'message' => 'Insufficient permissions'], 403); return; } diff --git a/inc/Smartling/WP/Controller/PostBasedWidgetControllerStd.php b/inc/Smartling/WP/Controller/PostBasedWidgetControllerStd.php index 130c4c28..438961d3 100644 --- a/inc/Smartling/WP/Controller/PostBasedWidgetControllerStd.php +++ b/inc/Smartling/WP/Controller/PostBasedWidgetControllerStd.php @@ -116,8 +116,13 @@ public function setNoOriginalFound($noOriginalFound) public function ajaxDownloadHandler(): void { - check_ajax_referer(self::AJAX_NONCE_ACTION, '_wpnonce'); + if (check_ajax_referer(self::AJAX_NONCE_ACTION, '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', self::AJAX_NONCE_ACTION, get_current_user_id())); + wp_send_json(['status' => self::RESPONSE_AJAX_STATUS_FAIL, 'message' => 'Invalid nonce'], 403); + return; + } if (!current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)); wp_send_json(['status' => self::RESPONSE_AJAX_STATUS_FAIL, 'message' => 'Insufficient permissions'], 403); return; } @@ -182,8 +187,13 @@ private function validateTargetBlog($blogId) public function ajaxUploadHandler() { - check_ajax_referer(self::AJAX_NONCE_ACTION, '_wpnonce'); + if (check_ajax_referer(self::AJAX_NONCE_ACTION, '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', self::AJAX_NONCE_ACTION, get_current_user_id())); + wp_send_json(['status' => self::RESPONSE_AJAX_STATUS_FAIL, 'message' => 'Invalid nonce'], 403); + return; + } if (!current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_WIDGET_CAP)); wp_send_json(['status' => self::RESPONSE_AJAX_STATUS_FAIL, 'message' => 'Insufficient permissions'], 403); return; } diff --git a/inc/Smartling/WP/Controller/TaxonomyLinksController.php b/inc/Smartling/WP/Controller/TaxonomyLinksController.php index fd5bf9d5..4f1d4d63 100644 --- a/inc/Smartling/WP/Controller/TaxonomyLinksController.php +++ b/inc/Smartling/WP/Controller/TaxonomyLinksController.php @@ -152,8 +152,13 @@ private function getMappedTerms() public function linkTaxonomies($data) { - $this->wordpressProxy->check_ajax_referer(self::NONCE_ACTION, '_wpnonce'); + if ($this->wordpressProxy->check_ajax_referer(self::NONCE_ACTION, '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', self::NONCE_ACTION, get_current_user_id())); + $this->wordpressProxy->wp_send_json_error(['message' => 'Invalid nonce'], 403); + return; + } if (!$this->wordpressProxy->current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_MENU_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_MENU_CAP)); $this->wordpressProxy->wp_send_json_error(['message' => 'Insufficient permissions'], 403); return; } diff --git a/inc/Smartling/WP/Controller/TestRunController.php b/inc/Smartling/WP/Controller/TestRunController.php index 047fab13..916b6e25 100644 --- a/inc/Smartling/WP/Controller/TestRunController.php +++ b/inc/Smartling/WP/Controller/TestRunController.php @@ -152,8 +152,13 @@ public function getBlogs(): array public function testRun($data): void { - check_ajax_referer('smartling_test_run', '_wpnonce'); + if (check_ajax_referer('smartling_test_run', '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', 'smartling_test_run', get_current_user_id())); + wp_send_json_error(['message' => 'Invalid nonce'], 403); + return; + } if (!current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_PROFILE_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_PROFILE_CAP)); wp_send_json_error(['message' => 'Insufficient permissions'], 403); return; } diff --git a/inc/Smartling/WP/Controller/VisualConfiguratorPage.php b/inc/Smartling/WP/Controller/VisualConfiguratorPage.php index 67978e92..70bf5f5c 100644 --- a/inc/Smartling/WP/Controller/VisualConfiguratorPage.php +++ b/inc/Smartling/WP/Controller/VisualConfiguratorPage.php @@ -2,6 +2,7 @@ namespace Smartling\WP\Controller; +use Smartling\Helpers\LoggerSafeTrait; use Smartling\Helpers\PluginInfo; use Smartling\Helpers\SmartlingUserCapabilities; use Smartling\Helpers\WordpressFunctionProxyHelper; @@ -12,6 +13,8 @@ class VisualConfiguratorPage extends ControllerAbstract implements WPHookInterface { + use LoggerSafeTrait; + public const SLUG = 'smartling_visual_configurator'; public const NONCE_ACTION = 'smartling_visual_configurator'; public const ACTION_LIST_RULES = 'smartling_visual_configurator_list_rules'; @@ -87,7 +90,7 @@ public function enqueue(string $hook): void public function ajaxListRules(): void { - if (!$this->verifyNonce()) { + if (!$this->verifyNonceAndCapabilities()) { return; } $this->rulesManager->loadData(); @@ -100,7 +103,7 @@ public function ajaxListRules(): void public function ajaxSaveRule(): void { - if (!$this->verifyNonce()) { + if (!$this->verifyNonceAndCapabilities()) { return; } try { @@ -141,7 +144,7 @@ public function ajaxSaveRule(): void public function ajaxResolveType(): void { - if (!$this->verifyNonce()) { + if (!$this->verifyNonceAndCapabilities()) { return; } $id = isset($_POST['id']) ? (int)$_POST['id'] : 0; @@ -159,7 +162,7 @@ public function ajaxResolveType(): void public function ajaxDeleteRule(): void { - if (!$this->verifyNonce()) { + if (!$this->verifyNonceAndCapabilities()) { return; } $id = isset($_POST['id']) && is_string($_POST['id']) @@ -177,10 +180,15 @@ public function ajaxDeleteRule(): void $this->wpProxy->wp_send_json_success(['id' => $id]); } - private function verifyNonce(): bool + private function verifyNonceAndCapabilities(): bool { - $this->wpProxy->check_ajax_referer(self::NONCE_ACTION, '_wpnonce'); + if ($this->wpProxy->check_ajax_referer(self::NONCE_ACTION, '_wpnonce', false) === false) { + $this->getLogger()->warning(sprintf('Invalid nonce for action "%s" from userId=%d', self::NONCE_ACTION, get_current_user_id())); + $this->wpProxy->wp_send_json_error(['message' => 'Invalid nonce'], 403); + return false; + } if (!$this->wpProxy->current_user_can(SmartlingUserCapabilities::SMARTLING_CAPABILITY_PROFILE_CAP)) { + $this->getLogger()->warning(sprintf('User %d lacks capability "%s"', get_current_user_id(), SmartlingUserCapabilities::SMARTLING_CAPABILITY_PROFILE_CAP)); $this->wpProxy->wp_send_json_error(['message' => 'Insufficient permissions'], 403); return false; } From f29bbeab4f525c79042534c3b5abfc2447765e3c Mon Sep 17 00:00:00 2001 From: Vitalii Solovei Date: Fri, 5 Jun 2026 20:04:10 +0200 Subject: [PATCH 2/2] add readme (WP-1003) Co-Authored-By: Claude Sonnet 4.6 --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 523b6981..ed862097 100755 --- a/readme.txt +++ b/readme.txt @@ -63,6 +63,7 @@ Additional information on the Smartling Connector for WordPress can be found [he == Changelog == = 5.5.2 = +* Added visual configurator for JSON metadata fields * Added "Check All" and "Uncheck All" buttons to the related assets list = 5.5.1 =