Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/syncee-global-dropshipping/Syncee.php
+++ b/syncee-global-dropshipping/Syncee.php
@@ -1,203 +1,186 @@
-<?php
-
-class Syncee
-{
-
- private static $instance = null;
- private $plugin_path;
- private $plugin_url;
- private $text_domain = 'syncee';
-
- /**
- * Creates or returns an instance of this class.
- */
- public static function get_instance()
- {
- // If an instance hasn't been created and set to $instance create an instance and set it to $instance.
- if (null == self::$instance) {
- self::$instance = new self;
- }
-
- return self::$instance;
- }
-
- /**
- * Initializes the plugin by setting localization, hooks, filters, and administrative functions.
- */
- private function __construct()
- {
- $this->plugin_path = plugin_dir_path(__FILE__);
- $this->plugin_url = plugin_dir_url(__FILE__);
-
- load_plugin_textdomain($this->text_domain, false, $this->plugin_path . 'lang');
-
- $this->init_rests();
-
- add_action('admin_enqueue_scripts', array($this, 'register_scripts'));
- add_action('admin_enqueue_scripts', array($this, 'register_styles'));
-
- add_action('wp_enqueue_scripts', array($this, 'register_scripts'));
- add_action('wp_enqueue_scripts', array($this, 'register_styles'));
-
- register_activation_hook(__FILE__, array($this, 'activation'));
- register_deactivation_hook(__FILE__, array($this, 'deactivation'));
-
- $this->run_plugin();
- }
-
- public function get_plugin_url()
- {
- return $this->plugin_url;
- }
-
- public function get_plugin_path()
- {
- return $this->plugin_path;
- }
-
- /**
- * Place code that runs at plugin activation here.
- */
- public function activation()
- {
- }
-
- /**
- * Place code that runs at plugin deactivation here.
- */
- public function deactivation()
- {
-
- }
-
- /**
- * Enqueue and register JavaScript files here.
- */
- public function register_scripts()
- {
-
- if (!isset($_GET['page']) || strpos($_GET['page'], 'syncee') === false)
- return;
-
- wp_enqueue_script(
- 'syncee-frontend-js',
- plugins_url('/JS/index.js', __FILE__),
- ['jquery'],
- time(),
- true
- );
-
- wp_enqueue_script(
- 'syncee-frontend-js-sweetalert',
- plugins_url('/JS/sweetalert.js', __FILE__)
- );
-
- //Data for frontend
- wp_localize_script(
- 'syncee-frontend-js',
- 'syncee_globals',
- [
- 'rest_url' => get_option('siteurl') . SYNCEE_RETAILER_REST_PATH,
- 'site_url' => get_option('siteurl'),
- 'syncee_access_token' => get_option('syncee_access_token', false),
- 'syncee_user_token' => get_option('syncee_user_token', false),
- 'data_to_syncee_installer' => get_option('data_to_syncee_installer', false),
- 'syncee_url' => SYNCEE_URL,
- 'syncee_installer_url' => SYNCEE_INSTALLER_URL,
- 'img_dir_url' => plugins_url('/img/', __FILE__),
- 'syncee_retailer_nonce' => wp_create_nonce( 'wp_rest' ),
- ]
- );
- }
-
- /**
- * Enqueue and register CSS files here.
- */
- public function register_styles()
- {
- if (isset($_GET['page']))
- if (strpos($_GET['page'], 'syncee') !== false)
- // wp_enqueue_style('bootstrap', plugins_url('/View/bootstrap.css', __FILE__));
- wp_enqueue_style('bootstrap', plugins_url('/View/index.css', __FILE__));
-
- }
-
- public function displayInterface()
- {
- echo '<div class="wrap js-syncee-admin-interface">';
- esc_html_e('Loading, please wait...', 'syncee');
- echo '</div>';
- }
-
- function registerMenu()
- {
- $icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMjQyIDIwNzAuNyI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogIzI4NmRmODsKICAgICAgfQogICAgPC9zdHlsZT4KICA8L2RlZnM+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJtMjI0MS43LDE2NTcuM0wyMDA2LjUsMEgyMzUuNUwuMywxNjU3LjNjLS4yLDEuMi0uMywyLjUtLjMsMy43LDEsMTg1LjgsMTQ0LjEsNDA5LjcsMzI5LjYsNDA5LjdoMTU4Mi44YzE4NS41LDAsMzI4LjYtMjIzLjksMzI5LjYtNDA5LjcsMC0xLjMsMC0yLjUtLjMtMy43Wk01NDUuNiw4NTIuNGMzNS4zLTE0MC4yLDExMi4zLTI1My41LDIzMy40LTMzMiwxOTkuNy0xMjkuNiw0MDcuMS0xMzQuNSw2MTMuNy0xOC4xLDU3LjcsMzIuNSwxMDYuMSw4MS44LDE2NCwxMjcuNSwzNy4yLTI4LjMsMTMxLjYtMTAxLjksMTMxLjYtMTAxLjksMCwwLDcuMywyODYuOCwxMS41LDQzMC42LTEzOC44LTM5LjUtMjY5LjMtNzYuNi00MTEuMS0xMTYuOSw1MC40LTQwLjMsOTEuMy03My4xLDEzNC44LTEwNy45LTU5LjYtNzQuOC0xMzUuOS0xMjIuNy0yMjgtMTQyLjctMjI1LjgtNDguOS00MjkuNSw3My40LTQ5NC42LDI5NC40LTE5LjYsNjYuNS03NS42LDkxLjUtMTI3LjEsNTcuMS0zMy44LTIyLjYtMzYuNi01Ni4zLTI4LjEtOTAuMVptMTE1MS4yLDM1My45Yy01MS4zLDIxOC4yLTI0OC41LDM5My4xLTQ4MS40LDQyMS44LTE5Mi45LDIzLjgtMzU3LjQtMzcuOC00OTIuOS0xNzYuOS05LTkuMy0xNy40LTE5LjItMjktMzIuMi00NC45LDM0LjEtMTM3LjcsMTA0LjQtMTM3LjcsMTA0LjQsMCwwLTguNi0yODMuNy0xMi45LTQyNy40LDEzOC44LDM5LjUsMjY5LjMsNzYuNiw0MTEuMiwxMTYuOS01MC42LDQwLjQtOTEuNSw3My4xLTEzNS40LDEwOC4yLDc4LjQsOTMuNCwxNzcuMSwxNDcuOCwyOTcuOSwxNTIsMjEyLjksNy40LDM2My44LTEwNC4zLDQyNi0zMDgsMTUuNi01MS4yLDU4LjMtNzguNSwxMDIuNC02NS41LDQ0LjUsMTMsNjQuMyw1My44LDUxLjgsMTA2LjdaIi8+Cjwvc3ZnPg==';
-
- add_menu_page(
- "Syncee",
- "Syncee",
- "manage_options",
- "syncee",
- array($this, "synceeMenu"),
- $icon,
- '55.5'
- );
- }
-
- function synceeMenu()
- {
- printf((file_get_contents(__DIR__ . '/View/index.php')));
- }
-
- function okToActivateSynceePlugin()
- {
- return in_array('woocommerce/woocommerce.php', get_option('active_plugins'));
- }
-
- function uninstallSynceePlugin()
- {
- if (in_array('Syncee/plugin.php', get_option('active_plugins')))
- deactivate_plugins(['Syncee/plugin.php']);
- if (in_array('syncee-global-dropshipping', get_option('active_plugins')))
- deactivate_plugins(['syncee-global-dropshipping/plugin.php']);
-
- }
-
- function sendErrorMessage($title, $desc)
- {
- printf('<div class="error">
- <p>' .
- esc_html__($title)
- . '</p>
- <p>
- <b>Error: </b>' . esc_html__($desc)
- . '</p>
- </div>');
- }
-
- function removePluginActivatedMessage()
- {
- unset($_GET['activate'], $_GET['error']);
- }
-
- /**
- * Place code for your plugin's functionality here.
- */
- private function run_plugin()
- {
-// if ($this->okToActivateSynceePlugin()) {
- add_action('admin_menu', array($this, 'registerMenu'));
-// } else {
-// $this->uninstallSynceePlugin();
-// $this->removePluginActivatedMessage();
-// $this->sendErrorMessage('Syncee plugin', 'WooCoommerce needs to be installed and activated before you can activate Syncee plugin.');
-// }
- }
-
- private function init_rests()
- {
- include_once SYNCEE_PLUGIN_DIR . '/includes/RestForSyncee.php';
- }
-}
-
-Syncee::get_instance();
+<?php
+
+class Syncee
+{
+
+ private static $instance = null;
+ private $plugin_path;
+ private $plugin_url;
+
+ /**
+ * Creates or returns an instance of this class.
+ */
+ public static function get_instance()
+ {
+ // If an instance hasn't been created and set to $instance create an instance and set it to $instance.
+ if (null == self::$instance) {
+ self::$instance = new self;
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Initializes the plugin by setting localization, hooks, filters, and administrative functions.
+ */
+ private function __construct()
+ {
+ $this->plugin_path = plugin_dir_path(__FILE__);
+ $this->plugin_url = plugin_dir_url(__FILE__);
+
+ $this->init_rests();
+
+ add_action('admin_enqueue_scripts', array($this, 'register_scripts'));
+ add_action('admin_enqueue_scripts', array($this, 'register_styles'));
+
+ $this->run_plugin();
+ }
+
+ public function get_plugin_url()
+ {
+ return $this->plugin_url;
+ }
+
+ public function get_plugin_path()
+ {
+ return $this->plugin_path;
+ }
+
+ /**
+ * Enqueue and register JavaScript files here.
+ */
+ public function register_scripts($hook_suffix = '')
+ {
+ if (!is_admin()) {
+ return;
+ }
+ if (!current_user_can('manage_options')) {
+ return;
+ }
+ if ('toplevel_page_syncee' !== $hook_suffix) {
+ return;
+ }
+
+ wp_enqueue_script(
+ 'syncee-frontend-js',
+ plugins_url('/JS/index.js', __FILE__),
+ ['jquery'],
+ SYNCEE_PLUGIN_VERSION,
+ true
+ );
+
+ wp_enqueue_script(
+ 'syncee-frontend-js-sweetalert',
+ plugins_url('/JS/sweetalert.js', __FILE__),
+ [],
+ SYNCEE_PLUGIN_VERSION
+ );
+
+ // SECURITY: sensitive options (syncee_access_token, syncee_user_token,
+ // data_to_syncee_installer) MUST NOT be localized here. JS reads them
+ // from the capability-gated getDataForFrontend REST endpoint.
+ wp_localize_script(
+ 'syncee-frontend-js',
+ 'syncee_globals',
+ [
+ 'rest_url' => esc_url_raw(get_option('siteurl') . SYNCEE_RETAILER_REST_PATH),
+ 'site_url' => esc_url_raw(get_option('siteurl')),
+ 'syncee_url' => SYNCEE_URL,
+ 'syncee_installer_url' => SYNCEE_INSTALLER_URL,
+ 'img_dir_url' => plugins_url('/img/', __FILE__),
+ 'syncee_retailer_nonce' => wp_create_nonce('wp_rest'),
+ ]
+ );
+ }
+
+ /**
+ * Enqueue and register CSS files here.
+ */
+ public function register_styles($hook_suffix = '')
+ {
+ if (!is_admin()) {
+ return;
+ }
+ if (!current_user_can('manage_options')) {
+ return;
+ }
+ if ('toplevel_page_syncee' !== $hook_suffix) {
+ return;
+ }
+
+ wp_enqueue_style('syncee-admin-css', plugins_url('/View/index.css', __FILE__), [], SYNCEE_PLUGIN_VERSION);
+ }
+
+ public function displayInterface()
+ {
+ echo '<div class="wrap js-syncee-admin-interface">';
+ esc_html_e('Loading, please wait...', 'syncee');
+ echo '</div>';
+ }
+
+ function registerMenu()
+ {
+ $icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMjQyIDIwNzAuNyI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogIzI4NmRmODsKICAgICAgfQogICAgPC9zdHlsZT4KICAKICAKICAKICAGPC9zdHlsZT4KICAKICAKICAGPC9kZWZzPgogIDxwYXRoIGNsYXNzPSJjbHMtMSIgZD0ibTIyNDEuNywxNjU3LjNMMjAwNi41LDBIMjM1LjVMLjMsMTY1Ny4zYy0uMiwxLjItLjMsMi41LS4zLDMuNywxLDE4NS44LDE0NC4xLDQwOS43LDMyOS42LDQwOS43aDE1ODIuOGMxODUuNSwwLDMyOC42LTIyMy45LDMyOS42LTQwOS43LDAtMS4zLDAtMi41LS4zLTMuN1o1NDUuNiw4NTIuNGMzNS4zLTE0MC4yLDExMi4zLTI1My41LDIzMy40LTMzMiwxOTkuNy0xMjkuNiw0MDcuMS0xMzQuNSw2MTMuNy0xOC4xLDU3LjcsMzIuNSwxMDYuMSw4MS44LDE2NCwxMjcuNSwzNy4yLTI4LjMsMTMxLjYtMTAxLjksMTMxLjYtMTAxLjksMCwwLDcuMywyODYuOCwxMS41LDQzMC42LTEzOC44LTM5LjUtMjY5LjMtNzYuNi00MTEuMS0xMTYuOSw1MC40LTQwLjMsOTEuMy03My4xLDEzNC44LTEwNy45LTU5LjYtNzQuOC0xMzUuOS0xMjIuNy0yMjgtMTQyLjctMjI1LjgtNDguOS00MjkuNSw3My40LTQ5NC42LDI5NC40LTE5LjYsNjYuNS03NS42LDkxLjUtMTI3LjEsNTcuMS0zMy44LTIyLjYtMzYuNi01Ni4zLTI4LjEtOTAuMVptMTE1MS4yLDM1My45Yy01MS4zLDIxOC4yLTI0OC41LDM5My4xLTQ4MS40LDQyMS44LTE5Mi45LDIzLjgtMzU3LjQtMzcuOC00OTIuOS0xNzYuOS05LTkuMy0xNy40LTE5LjItMjktMzIuMi00NC45LDM0LjEtMTM3LjcsMTA0LjQtMTM3LjcsMTA0LjQsMCwwLTguNi0yODMuNy0xMi45LTQyNy40LDEzOC44LDM5LjUsMjY5LjMsNzYuNiw0MTEuMiwxMTYuOS01MC42LDQwLjQtOTEuNSw3My4xLTEzNS40LDEwOC4yLDc4LjQsOTMuNCwxNzcuMSwxNDcuOCwyOTcuOSwxNTIsMjEyLjksNy40LDM2My44LTEwNC4zLDQyNi0zMDgsMTUuNi01MS4yLDU4LjMtNzguNSwxMDIuNC02NS41LDQ0LjUsMTMsNjQuMyw1My44LDUxLjgsMTA2LjdaIi8+Cjwvc3ZnPg==';
+
+ add_menu_page(
+ "Syncee",
+ "Syncee",
+ "manage_options",
+ "syncee",
+ array($this, "synceeMenu"),
+ $icon,
+ '55.5'
+ );
+ }
+
+ function synceeMenu()
+ {
+ $img_url = plugins_url('/img/', SYNCEE_PLUGIN_DIR . '/plugin.php');
+ include __DIR__ . '/View/index.php';
+ }
+
+ function okToActivateSynceePlugin()
+ {
+ return in_array('woocommerce/woocommerce.php', get_option('active_plugins'));
+ }
+
+ function uninstallSynceePlugin()
+ {
+ if (in_array('Syncee/plugin.php', get_option('active_plugins')))
+ deactivate_plugins(['Syncee/plugin.php']);
+ if (in_array('syncee-global-dropshipping', get_option('active_plugins')))
+ deactivate_plugins(['syncee-global-dropshipping/plugin.php']);
+
+ }
+
+ function sendErrorMessage($title, $desc)
+ {
+ echo '<div class="error"><p>' . esc_html($title) . '</p><p><b>Error: </b>' . esc_html($desc) . '</p></div>';
+ }
+
+ function removePluginActivatedMessage()
+ {
+ unset($_GET['activate'], $_GET['error']);
+ }
+
+ /**
+ * Place code for your plugin's functionality here.
+ */
+ private function run_plugin()
+ {
+// if ($this->okToActivateSynceePlugin()) {
+ add_action('admin_menu', array($this, 'registerMenu'));
+// } else {
+// $this->uninstallSynceePlugin();
+// $this->removePluginActivatedMessage();
+// $this->sendErrorMessage('Syncee plugin', 'WooCoommerce needs to be installed and activated before you can activate Syncee plugin.');
+// }
+ }
+
+ private function init_rests()
+ {
+ include_once SYNCEE_PLUGIN_DIR . '/includes/RestForSyncee.php';
+ }
+}
+
+Syncee::get_instance();
--- a/syncee-global-dropshipping/View/index.php
+++ b/syncee-global-dropshipping/View/index.php
@@ -1,148 +1,88 @@
-<?php
-?>
-
-
-<html lang="en">
-<header>
- <style>
- .syncee-logo-container {
- width: 300pt;
- }
-
- .syncee-logo {
- width: 200pt;
- margin: 25px;
-
- }
-
- .syncee-table {
- border-collapse: collapse;
- }
-
- .syncee-td, .syncee-th {
- border: 1px solid #999;
- padding: 0.5rem;
- text-align: left;
- }
-
- .syncee-body {
-
- }
-
- .syncee-button {
- display: inline-block;
- font-weight: 400;
- line-height: 1.5;
- color: #212529;
- text-align: center;
- text-decoration: none;
- vertical-align: middle;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- user-select: none;
- background-color: transparent;
- border: 0 solid transparent;
- border-radius: 100px;
- font-size: 14px;
- padding: 0 36px;
- min-height: 36px;
- }
-
- .syncee-button-secondary {
- color: #fff;
- background-color: #0d6efd;
- /*border-color: #0d6efd;*/
- }
-
- .syncee-button-warning {
- color: #EF5350;
- background-color: #FFCDD2;
- /*border-color: #FFCDD2;*/
- }
-
- #registerToWoocommerce, #registerToSyncee, #openSyncee {
- display: none;
- }
-
- </style>
-</header>
-
-<body class="syncee-body">
-
-<div class="syncee-logo-container">
- <img src="" alt="syncee logo" class="syncee-logo" id="syncee-logo">
-</div>
-<div id="requirementsTable"></div>
-
-<div>
- <div>
-
-
- <div id="registerToWoocommerce">
- <h2>Sign up Syncee to Woocommerce</h2>
- <p>You have to allow Woocommerce access for Syncee.</p>
- <button id="registerToWoocommerceButton" class="syncee-button syncee-button-secondary">Sign up Syncee to
- Woocommerce
- </button>
- <br>
- <br>
- </div>
-
-
- <div id="registerToSyncee">
- <h2>Sign up to Syncee</h2>
- <p>You have to sign up to the Syncee.</p>
- <button id="registerToSynceeButton" class="syncee-button syncee-button-secondary">Sign up to Syncee</button>
- <br>
- <br>
- </div>
-
-
- <div id="openSyncee">
- <p>Your store has been successfully connected to your Syncee account.</p>
- <button id="openSynceeButton" class="syncee-button syncee-button-secondary">Go to Syncee</button>
- <button id="uninstallEcomButton" class="syncee-button syncee-button-warning">Disconnect from Syncee</button>
- <br>
- <br>
- </div>
-
-
- <div id="refresh">
- <button id="refreshButton" class="syncee-button">Refresh</button>
- <br>
- <br>
- </div>
-
-
- <div id="support-team">
- <br>
- <p>If you have any questions or need assistance, contact the Syncee team at support@syncee.co</p>
- <br>
-
- </div>
- <div>
- <a target="_blank" href="https://help.syncee.co/en/articles/5074038-how-to-install-syncee-to-your-wordpress-store-woocommerce-integration" class="syncee-button">Integration</a>
- <a target="_blank" href="https://help.syncee.co/en/articles/6294863-woocommerce-system-requirements" class="syncee-button">Requirements</a>
- </div>
-
- </div>
-</div>
-</body>
-</html>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+<?php
+/**
+ * Syncee admin page template. Rendered inside the WP admin shell via
+ * Syncee::synceeMenu(); MUST NOT include outer <html>/<body>.
+ *
+ * Expects $img_url in scope (set by the caller).
+ *
+ * @var string $img_url Trailing-slash URL of the plugin's img/ directory.
+ */
+
+if (!defined('ABSPATH')) {
+ exit;
+}
+?>
+<div class="wrap syncee-admin">
+ <h1 class="screen-reader-text"><?php esc_html_e('Syncee', 'syncee'); ?></h1>
+
+ <div class="syncee-logo-container">
+ <img
+ src="<?php echo esc_url($img_url . 'syncee-logo-600x.png'); ?>"
+ alt="<?php esc_attr_e('Syncee', 'syncee'); ?>"
+ class="syncee-logo"
+ id="syncee-logo"
+ >
+ </div>
+
+ <div id="requirementsTable"></div>
+
+ <div id="registerToWoocommerce" class="syncee-step">
+ <h2><?php esc_html_e('Sign up Syncee to WooCommerce', 'syncee'); ?></h2>
+ <p><?php esc_html_e('You have to allow WooCommerce access for Syncee.', 'syncee'); ?></p>
+ <p>
+ <button id="registerToWoocommerceButton" type="button" class="button button-primary button-hero">
+ <?php esc_html_e('Sign up Syncee to WooCommerce', 'syncee'); ?>
+ </button>
+ </p>
+ </div>
+
+ <div id="registerToSyncee" class="syncee-step">
+ <h2><?php esc_html_e('Sign up to Syncee', 'syncee'); ?></h2>
+ <p><?php esc_html_e('You have to sign up to Syncee.', 'syncee'); ?></p>
+ <p>
+ <button id="registerToSynceeButton" type="button" class="button button-primary button-hero">
+ <?php esc_html_e('Sign up to Syncee', 'syncee'); ?>
+ </button>
+ </p>
+ </div>
+
+ <div id="openSyncee" class="syncee-step">
+ <div class="notice notice-success inline">
+ <p><?php esc_html_e('Your store has been successfully connected to your Syncee account.', 'syncee'); ?></p>
+ </div>
+ <p class="syncee-actions">
+ <button id="openSynceeButton" type="button" class="button button-primary button-hero">
+ <?php esc_html_e('Go to Syncee', 'syncee'); ?>
+ </button>
+ <button id="uninstallEcomButton" type="button" class="button button-link-delete">
+ <?php esc_html_e('Disconnect from Syncee', 'syncee'); ?>
+ </button>
+ </p>
+ </div>
+
+ <p class="syncee-refresh">
+ <button id="refreshButton" type="button" class="button">
+ <?php esc_html_e('Refresh', 'syncee'); ?>
+ </button>
+ </p>
+
+ <p class="syncee-support">
+ <?php
+ printf(
+ /* translators: %s: support email link */
+ esc_html__('If you have any questions or need assistance, contact the Syncee team at %s.', 'syncee'),
+ '<a href="mailto:support@syncee.co">support@syncee.co</a>'
+ );
+ ?>
+ </p>
+
+ <p class="syncee-help-links">
+ <a target="_blank" rel="noopener" href="https://help.syncee.co/en/articles/5074038-how-to-install-syncee-to-your-wordpress-store-woocommerce-integration">
+ <?php esc_html_e('Integration guide', 'syncee'); ?>
+ </a>
+ <span aria-hidden="true"> | </span>
+ <a target="_blank" rel="noopener" href="https://help.syncee.co/en/articles/6294863-woocommerce-system-requirements">
+ <?php esc_html_e('Requirements', 'syncee'); ?>
+ </a>
+ </p>
+</div>
--- a/syncee-global-dropshipping/includes/RequirementsForSyncee.php
+++ b/syncee-global-dropshipping/includes/RequirementsForSyncee.php
@@ -7,8 +7,6 @@
class RequirementsForSyncee
{
- public static $x = 10;
-
/**
* Checks if cURL is activated on php installation.
*
@@ -16,12 +14,12 @@
*/
public static function checkCurlForSyncee()
{
- if (!in_array('curl', get_loaded_extensions())) {
+ if (!extension_loaded('curl')) {
return array(
'title' => __('PHP cURL', 'syncee'),
'pass' => false,
'reason' => __('PHP cURL seems to be disabled or not installed on your server.', 'syncee'),
- 'solution' => __('Please activate cURL to use the syncee plugin. <br>')
+ 'solution' => __('Please activate cURL to use the syncee plugin. <br>', 'syncee')
);
}
@@ -38,13 +36,14 @@
*/
public static function checkSSLConnectionForSyncee()
{
- if (!getenv('IS_DEV') && (!isset($_SERVER['HTTPS']) || empty($_SERVER['HTTPS']) || 'on' !== strtolower($_SERVER['HTTPS']))) {
+ if (!getenv('IS_DEV') && !is_ssl()) {
return array(
'title' => __('SSL Connection', 'syncee'),
'pass' => false,
'reason' => __('You are not using a SSL connection', 'syncee'),
'solution' => __(
- 'Please set up a HTTPS certificate to use syncee.<br>'
+ 'Please set up a HTTPS certificate to use syncee.<br>',
+ 'syncee'
),
);
}
--- a/syncee-global-dropshipping/includes/RestForSyncee.php
+++ b/syncee-global-dropshipping/includes/RestForSyncee.php
@@ -1,162 +1,189 @@
-<?php
-
-
-class RestForSyncee
-{
- private $namespace = 'syncee/retailer/v1';
- private $endpoints =
- [
- 'POST' => [
- 'callbackFromWoocommerce' => false,
- 'saveAccessTokenFromSyncee' => false,
- 'saveTokenFromSyncee' => false,
- 'uninstallEcom' => false,
- ],
- 'GET' => [
- 'getCallbackData' => false,
- 'getDataForFrontend' => true,
- 'getRequirements' => false,
- 'getShopData' => false,
- ],
- ];
-
- function __construct()
- {
- add_action('rest_api_init', array($this, 'registerEndpointsForSyncee'));
- }
-
-
- function registerEndpointsForSyncee()
- {
- foreach ($this->endpoints as $requestType => $endpoints) {
- foreach ($endpoints as $rest => $protected)
- register_rest_route(
- $this->namespace,
- $rest,
- [
- 'methods' => $requestType,
- 'callback' => array($this, $rest),
- 'permission_callback' => $protected ? function () {
- return current_user_can('edit_others_posts');
- } : '__return_true',
- ]
- );
- }
- }
-
- function callbackFromWoocommerce($request)
- {
- $postData = $request->get_body();
- if (!is_array($request->get_body()))
- $postData = json_decode($postData);
-
- $consumer_key = sanitize_text_field($postData->consumer_key);
- $consumer_secret = sanitize_text_field($postData->consumer_secret);
- $key_permissions = sanitize_text_field($postData->key_permissions);
- $user_id = sanitize_text_field($postData->user_id);
-
- if (is_string($consumer_key) && is_string($consumer_secret) && is_string($key_permissions)) {
- $registerData = [
- 'domain' => get_option('siteurl'),
- 'currency' => get_option('woocommerce_currency'),
- 'weightUnit' => get_option('woocommerce_weight_unit'),
- 'consumerKey' => $consumer_key,
- 'consumerSecret' => $consumer_secret,
- 'keyPermissions' => $key_permissions,
- 'userId' => $user_id
- ];
-
- update_option('data_to_syncee_installer', $registerData);
- wp_send_json_success();
- } else {
- wp_send_json_error();
- }
-
- }
-
-
- function getCallbackData()
- {
- $dataToInstaller = esc_html(get_option('data_to_syncee_installer'));
- wp_send_json_success($dataToInstaller);
- }
-
- function getShopData()
- {
- $shopData = esc_sql([
- 'domain' => get_option('siteurl'),
- 'currency' => get_option('woocommerce_currency'),
- 'weightUnit' => get_option('woocommerce_weight_unit')
- ]);
- wp_send_json_success($shopData);
- }
-
- function getRequirements()
- {
- include 'RequirementsForSyncee.php';
- $requirementsStatus = RequirementsForSyncee::getRequirementsStatusForSyncee();
- $rStatus = esc_sql($requirementsStatus);
- wp_send_json_success($rStatus);
- }
-
-
- function uninstallEcom()
- {
- $uninstallUrl = SYNCEE_INSTALLER_URL . '/api/woocommerce_auth/uninstall';
- $uninstallData = [
- 'domain' => get_option('siteurl'),
- 'access_token' => get_option('syncee_access_token'),
- 'syncee_user_token' => get_option('syncee_user_token'),
- ];
- $response = wp_safe_remote_post(
- $uninstallUrl,
- array(
- 'headers' => array(),
- 'body' => $uninstallData
- )
- );
-
- if ($response['response']['code'] === 200) {
- delete_option('syncee_access_token');
- delete_option('syncee_user_token');
- wp_send_json_success('Successfully uninstalled store in Syncee!', 200);
- } else {
- wp_send_json_error(esc_html($response['response']['message']), esc_html($response['response']['code']));
- }
- }
-
- function saveAccessTokenFromSyncee()
- {
- $accessToken = sanitize_text_field($_POST['accessToken']);
- update_option('syncee_access_token', $accessToken);
- wp_send_json_success(esc_html(get_option('syncee_access_token')));
- }
-
-
- function saveTokenFromSyncee()
- {
- $accessToken = sanitize_text_field($_POST['token']);
- update_option('syncee_user_token', $accessToken);
- wp_send_json_success(esc_html(get_option('syncee_user_token')));
- }
-
-
- function getDataForFrontend()
- {
- $response = [
- 'rest_url' => get_option('siteurl') . SYNCEE_RETAILER_REST_PATH,
- 'site_url' => get_option('siteurl'),
- 'syncee_access_token' => get_option('syncee_access_token', false),
- 'syncee_user_token' => get_option('syncee_user_token', false),
- 'data_to_syncee_installer' => get_option('data_to_syncee_installer', false),
- ];
-
- wp_send_json_success(esc_sql($response));
-
- }
-}
-
-new RestForSyncee();
-
-
-
+<?php
+
+
+class RestForSyncee
+{
+ private $namespace = 'syncee/retailer/v1';
+
+ function __construct()
+ {
+ add_action('rest_api_init', array($this, 'registerEndpointsForSyncee'));
+ }
+
+ function registerEndpointsForSyncee()
+ {
+ $routes = [
+ ['startInstallFlow', 'POST', [$this, 'permission_admin']],
+ ['callbackFromWoocommerce', 'POST', $this->require_state('woocommerce_auth')],
+ ['saveAccessTokenFromSyncee', 'POST', $this->require_state('syncee_install')],
+ ['saveTokenFromSyncee', 'POST', $this->require_state('syncee_install')],
+ ['uninstallEcom', 'POST', [$this, 'permission_admin']],
+ ['getRequirements', 'GET', [$this, 'permission_admin']],
+ ['getDataForFrontend', 'GET', [$this, 'permission_admin']],
+ ];
+
+ foreach ($routes as $route) {
+ list($endpoint, $method, $permission_callback) = $route;
+ register_rest_route(
+ $this->namespace,
+ $endpoint,
+ [
+ 'methods' => $method,
+ 'callback' => [$this, $endpoint],
+ 'permission_callback' => $permission_callback,
+ ]
+ );
+ }
+ }
+
+ /**
+ * Public on purpose: WP's REST router invokes the callable from outside
+ * this class scope, so PHP visibility rules require this be public.
+ */
+ public function permission_admin()
+ {
+ return current_user_can('manage_options');
+ }
+
+ /**
+ * Returns a closure usable as a REST permission_callback. The closure
+ * checks that a valid, unexpired, stage-matching state token was provided
+ * AND atomically consumes (deletes) it. Doing the delete here (rather than
+ * in the endpoint body) narrows the race window for replay attacks — two
+ * concurrent requests with the same token can no longer both pass the
+ * permission check.
+ */
+ private function require_state($required_stage)
+ {
+ return function (WP_REST_Request $request) use ($required_stage) {
+ $state = $request->get_param('state');
+ if (!is_string($state) || strlen($state) < 32) {
+ return false;
+ }
+ $key = 'syncee_state_' . hash('sha256', $state);
+ $stored_stage = get_transient($key);
+ if ($stored_stage !== $required_stage) {
+ return false;
+ }
+ delete_transient($key);
+ return true;
+ };
+ }
+
+ public function startInstallFlow(WP_REST_Request $request)
+ {
+ $stage = $request->get_param('stage');
+ if (!in_array($stage, ['woocommerce_auth', 'syncee_install'], true)) {
+ wp_send_json_error(['code' => 'invalid_stage'], 400);
+ }
+
+ $state = wp_generate_password(64, false);
+ set_transient('syncee_state_' . hash('sha256', $state), $stage, 15 * MINUTE_IN_SECONDS);
+
+ wp_send_json_success(['state' => $state]);
+ }
+
+ public function callbackFromWoocommerce(WP_REST_Request $request)
+ {
+ $postData = $request->get_json_params();
+ if (!is_array($postData)) {
+ // Fall back to manual decode for callers that don't set Content-Type: application/json.
+ $postData = json_decode($request->get_body(), true);
+ }
+ if (!is_array($postData)) {
+ wp_send_json_error(['code' => 'invalid_body'], 400);
+ }
+
+ $consumer_key = isset($postData['consumer_key']) ? sanitize_text_field($postData['consumer_key']) : '';
+ $consumer_secret = isset($postData['consumer_secret']) ? sanitize_text_field($postData['consumer_secret']) : '';
+ $key_permissions = isset($postData['key_permissions']) ? sanitize_text_field($postData['key_permissions']) : '';
+ $user_id = isset($postData['user_id']) ? sanitize_text_field($postData['user_id']) : '';
+
+ if ($consumer_key === '' || $consumer_secret === '' || $key_permissions === '') {
+ wp_send_json_error(['code' => 'missing_fields'], 400);
+ }
+
+ update_option('data_to_syncee_installer', [
+ 'domain' => get_option('siteurl'),
+ 'currency' => get_option('woocommerce_currency'),
+ 'weightUnit' => get_option('woocommerce_weight_unit'),
+ 'consumerKey' => $consumer_key,
+ 'consumerSecret' => $consumer_secret,
+ 'keyPermissions' => $key_permissions,
+ 'userId' => $user_id,
+ ]);
+
+ wp_send_json_success();
+ }
+
+ public function getRequirements(WP_REST_Request $request)
+ {
+ require_once __DIR__ . '/RequirementsForSyncee.php';
+ wp_send_json_success(RequirementsForSyncee::getRequirementsStatusForSyncee());
+ }
+
+ public function uninstallEcom(WP_REST_Request $request)
+ {
+ $response = wp_safe_remote_post(
+ SYNCEE_INSTALLER_URL . '/api/woocommerce_auth/uninstall',
+ [
+ 'body' => [
+ 'domain' => get_option('siteurl'),
+ 'access_token' => get_option('syncee_access_token'),
+ 'syncee_user_token' => get_option('syncee_user_token'),
+ ],
+ ]
+ );
+
+ if (is_wp_error($response)) {
+ wp_send_json_error(['code' => 'installer_unreachable', 'message' => $response->get_error_message()], 502);
+ }
+
+ $code = (int) wp_remote_retrieve_response_code($response);
+ if ($code !== 200) {
+ wp_send_json_error(
+ ['code' => 'installer_error', 'message' => wp_remote_retrieve_response_message($response)],
+ $code ?: 500
+ );
+ }
+
+ delete_option('syncee_access_token');
+ delete_option('syncee_user_token');
+ wp_send_json_success(['message' => 'Successfully uninstalled store in Syncee.']);
+ }
+
+ public function saveAccessTokenFromSyncee(WP_REST_Request $request)
+ {
+ $accessToken = sanitize_text_field((string) $request->get_param('accessToken'));
+ if ($accessToken === '') {
+ wp_send_json_error(['code' => 'missing_token'], 400);
+ }
+ update_option('syncee_access_token', $accessToken);
+
+ wp_send_json_success();
+ }
+
+ public function saveTokenFromSyncee(WP_REST_Request $request)
+ {
+ $accessToken = sanitize_text_field((string) $request->get_param('token'));
+ if ($accessToken === '') {
+ wp_send_json_error(['code' => 'missing_token'], 400);
+ }
+ update_option('syncee_user_token', $accessToken);
+
+ wp_send_json_success();
+ }
+
+ public function getDataForFrontend(WP_REST_Request $request)
+ {
+ wp_send_json_success([
+ 'rest_url' => esc_url_raw(get_option('siteurl') . SYNCEE_RETAILER_REST_PATH),
+ 'site_url' => esc_url_raw(get_option('siteurl')),
+ 'syncee_access_token' => get_option('syncee_access_token', false),
+ 'syncee_user_token' => get_option('syncee_user_token', false),
+ 'data_to_syncee_installer' => get_option('data_to_syncee_installer', false),
+ ]);
+ }
+}
+
+new RestForSyncee();
--- a/syncee-global-dropshipping/plugin.php
+++ b/syncee-global-dropshipping/plugin.php
@@ -3,7 +3,7 @@
/**
* Plugin Name: Syncee Premium Dropshipping & Wholesale
* Description: Find dropshipping and wholesale products from trusted US/CA/EU/AU suppliers, import them to [your WooCommerce store](https://syncee.com/woocommerce/).
- * Version: 1.0.27
+ * Version: 1.0.28
* Author: Syncee
* Author URI: https://syncee.com
*
@@ -15,7 +15,7 @@
}
// Define constants.
-define( 'SYNCEE_PLUGIN_VERSION', '1.0.27' );
+define( 'SYNCEE_PLUGIN_VERSION', '1.0.28' );
//DEMO
//define( 'SYNCEE_URL', 'https://demo.v5.syncee.io' );