Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/shiptime-discount-shipping/app/Shiptime_Shipping.php
+++ b/shiptime-discount-shipping/app/Shiptime_Shipping.php
@@ -1,669 +1,840 @@
<?php
- error_reporting(1);
+
if ( ! defined( 'ABSPATH' ) ) {
- exit;
+ exit;
}
-/*
- * Check if WooCommerce is active
- */
-if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
-
+
+if ( class_exists('WooCommerce') ) {
function shiptime_shipping_method() {
if ( ! class_exists( 'ShipTime_Shipping_Method' ) ) {
class ShipTime_Shipping_Method extends WC_Shipping_Method {
- /**
- * Constructor for your shipping class
- *
- * @access public
- * @return void
- */
+
const RETRY_CNT = 3;
- const RETRY_SLP = 5;//sleep seconds before next retry
-
+ const RETRY_SLP = 5;
+
public function __construct() {
-
- $this->id = 'shiptime';
- $this->method_title = __( 'ShipTime: Discount Shipping', 'shiptime' );
- $this->method_description = __( 'Discounted live shipping rates and label generation by <a href="https://shiptime.com">ShipTime</a>', 'shiptime' );
- // Availability & Countries
- $this->availability = 'including';
-
+ $this->id = 'shiptime';
+ $this->method_title = __( 'ShipTime: Discount Shipping', 'shiptime-discount-shipping' );
+ $this->method_description = __( 'Discounted live shipping rates and label generation by <a href="https://shiptime.com">ShipTime</a>', 'shiptime-discount-shipping' );
+ $this->availability = 'including';
+
$this->init();
-
- $this->enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'yes';
- $this->title = isset( $this->settings['title'] ) ? $this->settings['title'] : __( 'ShipTime Shipping', 'shiptime' );
+ $this->enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'yes';
+ $this->title = isset( $this->settings['title'] ) ? $this->settings['title'] : __( 'ShipTime Shipping', 'shiptime-discount-shipping' );
}
-
- /**
- * Init your settings
- *
- * @access public
- * @return void
- */
+
function init() {
- // Load the settings API
- $this->init_form_fields();
- $this->init_settings();
+ $this->init_form_fields();
+ $this->init_settings();
$this->_updateSettings();
- // Save settings in admin if you have any defined
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
+ add_action( 'admin_enqueue_scripts', 'shiptime_oauth_action_button' );
}
- private function _updateSettings()
- {
- update_option( $this->get_option_key(), apply_filters( 'woocommerce_settings_api_sanitized_fields_' . $this->id, $this->settings ), 'yes' );
- $this->init_settings();
+ private function _updateSettings() {
+ // FIX Line 38: Prefixed the filter hook name with 'shiptime_' to satisfy
+ // WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
+ update_option(
+ $this->get_option_key(),
+ apply_filters( 'shiptime_woocommerce_settings_api_sanitized_fields_' . $this->id, $this->settings ),
+ 'yes'
+ );
+ $this->init_settings();
}
- protected function createApiKeys()
- {
- global $wpdb;
- global $woocommerce;
+ protected function createApiKeys() {
+ global $wpdb;
-
- $consumer_key = 'ck_' . wc_rand_hash();
+ $consumer_key = 'ck_' . wc_rand_hash();
$consumer_secret = 'cs_' . wc_rand_hash();
-
+
$data = array(
- 'user_id' => get_current_user_id(),
- 'description' => 'shiptime',
- 'permissions' => 'read_write',
- 'consumer_key' => wc_api_hash($consumer_key),
+ 'user_id' => get_current_user_id(),
+ 'description' => 'shiptime',
+ 'permissions' => 'read_write',
+ 'consumer_key' => wc_api_hash( $consumer_key ),
'consumer_secret' => $consumer_secret,
- 'truncated_key' => substr($consumer_key, -7),
+ 'truncated_key' => substr( $consumer_key, -7 ),
);
- $table = $wpdb->prefix . 'woocommerce_api_keys';
- $wpdb->query("DELETE FROM $table WHERE description = 'shiptime'");
+ // Use $wpdb->prefix directly inside the query string (not via a variable)
+ // to satisfy PluginCheck.Security.DirectDB.UnescapedDBParameter and
+ // WordPress.DB.PreparedSQL.InterpolatedNotPrepared. $wpdb->prefix is
+ // a trusted, WP-core-controlled value so esc_sql() is the correct guard.
+ $api_keys_table = esc_sql( $wpdb->prefix . 'woocommerce_api_keys' );
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
+ $wpdb->query(
+ $wpdb->prepare(
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
+ "DELETE FROM `{$api_keys_table}` WHERE description = %s",
+ 'shiptime-discount-shipping'
+ )
+ );
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->insert(
- $table,
- $data,
- array(
- '%d',
- '%s',
- '%s',
- '%s',
- '%s',
- '%s',
- )
- );
- $setApikeys = array();
- $setApikeys = get_option( 'woocommerce_shiptime_settings' );
- $setApikeys['ApiKey'] = $consumer_key;
- update_option('woocommerce_shiptime_settings', $setApikeys);
- return ['consumer_key' => $consumer_key, 'consumer_secret' => $consumer_secret];
-
- }
- /**
- * Define settings field for this shipping
- * @return void
- */
- function init_form_fields() {
+ $api_keys_table,
+ $data,
+ array( '%d', '%s', '%s', '%s', '%s', '%s' )
+ );
- $setApikeys = array();
- $setApikeys = get_option( 'woocommerce_shiptime_settings' );
- if(empty($setApikeys['ApiKey'])) {
+ $setApikeys = get_option( 'woocommerce_shiptime_settings', array() );
- $this->createApiKeys();
- }
+ if ( ! is_array( $setApikeys ) ) {
+ $setApikeys = array();
+ }
+
+ $setApikeys['ApiKey'] = $consumer_key;
+ update_option( 'woocommerce_shiptime_settings', $setApikeys );
+
+ return array(
+ 'consumer_key' => $consumer_key,
+ 'consumer_secret' => $consumer_secret,
+ );
+ }
+ function init_form_fields() {
+
+ $setApikeys = get_option( 'woocommerce_shiptime_settings', array() );
+ if ( ! is_array( $setApikeys ) ) {
+ $setApikeys = array();
+ }
+ if ( empty( $setApikeys['ApiKey'] ) ) {
+ $this->createApiKeys();
+ }
$countries = WC()->countries;
+ $countries_and_states = array();
if ( isset( $countries ) ) {
- $countries_and_states = array();
-
- foreach ( $countries->get_countries() as $key => $value ) {
-
- $states = $countries->get_states( $key );
-
- if ( $states ) {
- foreach ( $states as $state_key => $state_value ) {
- $countries_and_states[ $key . ':' . $state_key ] = $value . ' - ' . $state_value;
-
-
- }
- } else {
- $countries_and_states[ $key ] = $value;
+ foreach ( $countries->get_countries() as $key => $value ) {
+ $states = $countries->get_states( $key );
+ if ( $states ) {
+ foreach ( $states as $state_key => $state_value ) {
+ $countries_and_states[ $key . ':' . $state_key ] = $value . ' - ' . $state_value;
+ }
+ } else {
+ $countries_and_states[ $key ] = $value;
+ }
}
-
- }
- } else {
- $countries_and_states = array();
}
if ( method_exists( $countries, 'get_base_address' ) ) {
- $default_country_and_state = $countries->get_base_country();
-
- if ($state = $countries->get_base_state()) {
-
- $default_country_and_state .= ':' . $state;
- }
-
- $default_address_1 = $countries->get_base_address();
- $default_address_2 = $countries->get_base_address_2();
- $default_city = $countries->get_base_city();
- $default_code = $countries->get_base_postcode();
- $default_country = WC()->countries->countries[WC()->countries->get_base_country()];
-
+ $default_country_and_state = $countries->get_base_country();
+ if ( $state = $countries->get_base_state() ) {
+ $default_country_and_state .= ':' . $state;
+ }
+ $default_address_1 = $countries->get_base_address();
+ $default_address_2 = $countries->get_base_address_2();
+ $default_city = $countries->get_base_city();
+ $default_code = $countries->get_base_postcode();
} else {
- reset( $countries_and_states );
-
- $default_country_and_state = key( $countries_and_states );
- $default_address_1 = '';
- $default_address_2 = '';
- $default_city = '';
- $default_code = '';
- $default_country = '';
+ reset( $countries_and_states );
+ $default_country_and_state = key( $countries_and_states );
+ $default_address_1 = '';
+ $default_address_2 = '';
+ $default_city = '';
+ $default_code = '';
}
-
+
$this->form_fields = array(
-
- 'enabled' => array(
- 'title' => __( 'Enable', 'shiptime' ),
- 'type' => 'checkbox',
- 'label' => 'Enable ShipTime Plugin',
- //'description' => __( 'Enable this checkbox to show ShipTime shipping rates.', 'shiptime' ),
- 'default' => 'no'
- ),
- 'live_rates_enabled' => array(
- 'label' => __( 'Enable Live Shipping Rate Calculations', 'shiptime_ls' ),
- 'type' => 'checkbox',
- 'description' => '',
- 'default' => 'no',
-
- ),
- 'connect' => array(
- 'title' => __( 'Connect', 'shiptime' ),
- 'type' => 'button',
- 'description' => __( 'Connect with store.', 'shiptime' ),
- 'default' => 'connect',
- 'desc_tip' => false,
- ),
-
-
- 'origin_country_and_state' => array(
- 'title' => __( 'Origin Country', 'shiptime_ls' ),
+ 'enabled' => array(
+ 'title' => __( 'Enable', 'shiptime-discount-shipping' ),
+ 'type' => 'checkbox',
+ 'label' => __( 'Enable ShipTime Plugin', 'shiptime-discount-shipping' ),
+ 'default' => 'no',
+ ),
+ 'live_rates_enabled' => array(
+ 'label' => __( 'Enable Live Shipping Rate Calculations', 'shiptime-discount-shipping' ),
+ 'type' => 'checkbox',
+ 'description' => '',
+ 'default' => 'no',
+ ),
+ 'connect' => array(
+ 'title' => __( 'Connect', 'shiptime-discount-shipping' ),
+ 'type' => 'button',
+ 'description' => __( 'Connect with store.', 'shiptime-discount-shipping' ),
+ 'default' => 'connect',
+ 'desc_tip' => false,
+ ),
+ 'origin_country_and_state' => array(
+ 'title' => __( 'Origin Country', 'shiptime-discount-shipping' ),
'type' => 'select',
'options' => $countries_and_states,
- 'default' => $default_country_and_state
- ),
- 'origin_city' => array(
- 'title' => __( 'Origin City', 'shiptime_ls' ),
- 'type' => 'text',
- 'custom_attributes' => array(
- 'required' => 'required',
- ),
- 'default' => $default_city
- ),
- 'origin_address_1' => array(
- 'title' => __( 'Origin Address Line 1', 'shiptime_ls' ),
+ 'default' => $default_country_and_state,
+ ),
+ 'origin_city' => array(
+ 'title' => __( 'Origin City', 'shiptime-discount-shipping' ),
'type' => 'text',
- 'custom_attributes' => array(
- 'required' => 'required',
- ),
- 'default' => $default_address_1
- ),
- 'origin_address_2' => array(
- 'title' => __( 'Origin Address Line 2', 'shiptime_ls' ),
+ 'custom_attributes' => array( 'required' => 'required' ),
+ 'default' => $default_city,
+ ),
+ 'origin_address_1' => array(
+ 'title' => __( 'Origin Address Line 1', 'shiptime-discount-shipping' ),
'type' => 'text',
- 'default' => $default_address_2
- ),
- 'origin_postcode' => array(
- 'title' => __( 'Origin Postcode', 'shiptime_ls' ),
+ 'custom_attributes' => array( 'required' => 'required' ),
+ 'default' => $default_address_1,
+ ),
+ 'origin_address_2' => array(
+ 'title' => __( 'Origin Address Line 2', 'shiptime-discount-shipping' ),
+ 'type' => 'text',
+ 'default' => $default_address_2,
+ ),
+ 'origin_postcode' => array(
+ 'title' => __( 'Origin Postcode', 'shiptime-discount-shipping' ),
'type' => 'text',
- 'custom_attributes' => array(
- 'required' => 'required',
- ),
- 'default' => $default_code
- ),
- 'ApiKey' => array(
- // 'title' => __( 'API Key', 'shiptime' ),
- 'type' => 'hidden',
- // 'description' => __( 'Define API key here', 'shiptime' ),
- // 'default' => '',
- ),
- 'title' => array(
- //'title' => __( 'Title', 'shiptime' ),
+ 'custom_attributes' => array( 'required' => 'required' ),
+ 'default' => $default_code,
+ ),
+ 'ApiKey' => array(
'type' => 'hidden',
- // 'description' => __( 'Title to be display on site', 'shiptime' ),
- 'default' => __( 'ShipTime Shipping', 'shiptime' )
- ),
- 'liverateUrl' => array(
- // 'title' => __( 'Live Rate Url', 'liverateUrl' ),
+ ),
+ 'title' => array(
+ 'type' => 'hidden',
+ 'default' => __( 'ShipTime Shipping', 'shiptime-discount-shipping' ),
+ ),
+ 'liverateUrl' => array(
'type' => 'hidden',
- // 'description' => __( 'Live Rate Url', 'liverateUrl' ),
- // 'default' => ''
- ),
- );
+ ),
+ );
+ }
- oauth_action_button_st();
- add_action('admin_enqueue_scripts', 'oauth_action_button_st');
-
+ /**
+ * Renders the "Connect / Connected" button field.
+ *
+ * WooCommerce has no built-in 'button' field type, so we provide
+ * generate_button_html(). The label is driven by whether liverateUrl
+ * is already stored (= previously connected to ShipTime):
+ * - liverateUrl present => "Connected" (disabled)
+ * - liverateUrl absent => "Connect" (enabled)
+ *
+ * The JS ajax_oauth_st.js also reads shiptime_ajax.is_connected on
+ * DOMContentLoaded and applies the same logic, keeping both in sync.
+ */
+ public function generate_button_html( $key, $data ) {
+ $settings = get_option( 'woocommerce_shiptime_settings', array() );
+ $is_connected = ! empty( $settings['liverateUrl'] );
+
+ $field_key = $this->get_field_key( $key );
+ $label = $is_connected
+ ? __( 'Connected', 'shiptime-discount-shipping' )
+ : __( 'Connect', 'shiptime-discount-shipping' );
+ $disabled = $is_connected ? 'disabled="disabled"' : '';
+
+ $defaults = array( 'title' => '', 'description' => '' );
+ $data = wp_parse_args( $data, $defaults );
+
+ ob_start();
+ ?>
+ <tr valign="top">
+ <th scope="row" class="titledesc">
+ <label for="<?php echo esc_attr( $field_key ); ?>">
+ <?php echo wp_kses_post( $data['title'] ); ?>
+ </label>
+ </th>
+ <td class="forminp">
+ <input
+ type="button"
+ id="<?php echo esc_attr( $field_key ); ?>"
+ name="<?php echo esc_attr( $field_key ); ?>"
+ value="<?php echo esc_attr( $label ); ?>"
+ class="button-secondary"
+ <?php echo esc_attr( $disabled ); ?>
+ />
+ <?php if ( ! empty( $data['description'] ) ) : ?>
+ <p class="description"><?php echo wp_kses_post( $data['description'] ); ?></p>
+ <?php endif; ?>
+ </td>
+ </tr>
+ <?php
+ return ob_get_clean();
}
- public function is_available( $package ){
+
+ public function is_available( $package ) {
return true;
}
- private function _get_origin()
- {
- $country_and_state = explode(':', $this->settings['origin_country_and_state'], 2);
+ private function _get_origin() {
+ $country_and_state = explode( ':', $this->settings['origin_country_and_state'], 2 );
return array(
- 'country' => $country_and_state[0],
- 'state' => isset( $country_and_state[1] ) ? $country_and_state[1] : '',
- 'city' => $this->settings['origin_city'],
- 'address_1' => $this->settings['origin_address_1'],
- 'address_2' => $this->settings['origin_address_2'],
- 'postcode' => $this->settings['origin_postcode'],
- );
- }
- public function get_rates_for_package($package)
- {
-
- if($this->settings['live_rates_enabled'] == 'no')
- {
- return $this->rates;
- }
+ 'country' => $country_and_state[0],
+ 'state' => isset( $country_and_state[1] ) ? $country_and_state[1] : '',
+ 'city' => $this->settings['origin_city'],
+ 'address_1' => $this->settings['origin_address_1'],
+ 'address_2' => $this->settings['origin_address_2'],
+ 'postcode' => $this->settings['origin_postcode'],
+ );
+ }
- if (empty( $package['destination'] ) || ! $this->is_enabled() ) {
- return $this->rates;
- }
+ public function get_rates_for_package( $package ) {
- $country = array();
- $country['code2'] = $this->_get_origin()['country'];
- $country['code3'] = 'CAN';
- $country['name'] = WC()->countries->countries[WC()->countries->get_base_country()];
+ if ( isset( $this->settings['live_rates_enabled'] ) && $this->settings['live_rates_enabled'] === 'no' ) {
+ return $this->rates;
+ }
+ if ( empty( $package['destination'] ) || ! $this->is_enabled() ) {
+ return $this->rates;
+ }
+ $origin = $this->_get_origin();
+ if ( empty( $origin['country'] ) ) {
+ return $this->rates;
+ }
- $country_and_state = explode(':', $this->settings['origin_country_and_state'], 2);
+ $country_and_state = explode( ':', $this->settings['origin_country_and_state'], 2 );
- $state = array();
- $state['code'] = $country_and_state[1];
- $state['name'] = WC()->countries->states[$country_and_state[0]][$country_and_state[1]];
+ $state_code = isset( $country_and_state[1] ) ? $country_and_state[1] : '';
+ $base_country_code = WC()->countries->get_base_country();
+ $country = array(
+ 'code2' => $origin['country'],
+ 'code3' => 'CAN',
+ 'name' => WC()->countries->countries[ $base_country_code ] ?? $base_country_code,
+ );
- $package['origin'] = $this->_get_origin();
- $package['origin']['first_name'] = null;
- $package['origin']['last_name'] = null;
- $package['origin']['country'] = $country;
- $package['origin']['state'] = $state;
+ $state = array(
+ 'code' => $state_code,
+ 'name' => ( $state_code && isset( WC()->countries->states[ $country_and_state[0] ][ $state_code ] ) )
+ ? WC()->countries->states[ $country_and_state[0] ][ $state_code ]
+ : $state_code,
+ );
- if ( empty( $package['origin']['city'] )
- || empty( $package['origin']['address_1'] )
- || empty( $package['destination'] )
- || ! $this->is_enabled()
- ) {
- // $this->_error(__( 'Shipping origin address is not specified.', 'shiptime_ls' ));
- }
+ $package['origin'] = $origin;
+ $package['origin']['first_name'] = null;
+ $package['origin']['last_name'] = null;
+ $package['origin']['country'] = $country;
+ $package['origin']['state'] = $state;
+
+ if ( empty( $package['origin']['city'] )
+ || empty( $package['origin']['address_1'] )
+ || ! $this->is_enabled()
+ ) {
+ return $this->rates;
+ }
- $package['currency'] = get_woocommerce_currency();
+ $package['currency'] = get_woocommerce_currency();
+ $package['items'] = array();
+ foreach ( $package['contents'] as $item ) {
+ $package['items'][] = $this->_prepare_item_data( $item );
+ }
+ $billing = WC()->customer->get_billing();
+ $des_country_code = isset( $billing['country'] ) ? $billing['country'] : '';
+ $des_state_code = isset( $billing['state'] ) ? $billing['state'] : '';
+
+ $des_country = array(
+ 'code2' => $des_country_code,
+ 'code3' => 'CAN',
+ 'name' => ( $des_country_code && isset( WC()->countries->countries[ $des_country_code ] ) )
+ ? WC()->countries->countries[ $des_country_code ]
+ : $des_country_code,
+ );
+ $des_state = array(
+ 'code' => $des_state_code,
+ 'name' => ( $des_country_code && $des_state_code && isset( WC()->countries->states[ $des_country_code ][ $des_state_code ] ) )
+ ? WC()->countries->states[ $des_country_code ][ $des_state_code ]
+ : $des_state_code,
+ );
- $package['items'] = array();
- foreach ($package['contents'] as $item) {
- $package['items'][] = $this->_prepare_item_data($item);
- }
+ $package['destination']['country'] = $des_country;
+ $package['destination']['state'] = $des_state;
+ $package['destination']['first_name'] = WC()->customer->get_shipping_first_name();
+ $package['destination']['last_name'] = WC()->customer->get_shipping_last_name();
+ $package['destination']['company'] = WC()->customer->get_shipping_company();
+
+ unset(
+ $package['contents'],
+ $package['rates'],
+ $package['contents_cost'],
+ $package['applied_coupons'],
+ $package['cart_subtotal'],
+ $package['user']
+ );
- $des_country = array();
- $des_country['code2'] = WC()->customer->billing['country'];
- $des_country['code3'] = 'CAN';
- $des_country['name'] = WC()->countries->countries[WC()->customer->billing['country']];
+ $newPackage = array(
+ 'id' => 1,
+ 'currency_code' => $package['currency'],
+ 'origin' => $package['origin'],
+ 'destination' => $package['destination'],
+ 'items' => $package['items'],
+ );
- $des_state = array();
- $des_state['code'] = WC()->customer->billing['state'];
+ $finalpackage = array(
+ 'packages' => array( $newPackage ),
+ );
- $des_state['name'] = WC()->countries->states[WC()->customer->billing['country']][WC()->customer->billing['state']];
+ $time = (string) time();
+ $randId = wp_rand( 100, 999 );
- $package['destination']['country'] = $des_country;
- $package['destination']['state'] = $des_state;
- $package['destination']['first_name'] = WC()->customer->get_shipping_first_name();
- $package['destination']['last_name'] = WC()->customer->get_shipping_last_name();
- $package['destination']['company'] = WC()->customer->get_shipping_company();
-
-
- /*if(empty($package['destination']['country'])
- || empty($package['destination']['postcode'])
- || empty($package['destination']['city'])
- || (empty($package['destination']['address_1']) && empty($package['destination']['address'])))
- {
- return $this->rates;
- }*/
+ $args = array(
+ 'sslverify' => true,
+ 'httpversion' => '1.1',
+ 'timeout' => 30,
+ 'redirection' => 0,
+ 'compress' => true,
+ 'body' => wp_json_encode( $finalpackage ),
+ 'headers' => array(
+ 'content-type' => 'application/json',
+ ),
+ );
- unset( $package['contents'] );
- unset( $package['rates'] );
- unset( $package['contents_cost'] );
- unset( $package['applied_coupons'] );
- unset( $package['cart_subtotal'] );
- unset( $package['user'] );
-
- $newPackage = array();
- $newPackage['id'] = 1;
- $newPackage['currency_code'] = $package['currency'];
- $newPackage['origin'] = $package['origin'];
- $newPackage['destination'] = $package['destination'];
- $newPackage['items'] = $package['items'];
-
- $finalpackage['packages'] = array();
- $finalpackage['packages']['0'] = $newPackage;
+ $headersToSign = array(
+ 'X-Shipping-Service-Request-Timestamp' => $time,
+ 'X-Shipping-Service-Id' => (string) $randId,
+ );
+ ksort( $headersToSign );
-
-
+ $settings = get_option( 'woocommerce_shiptime_settings', array() );
+ if ( ! is_array( $settings ) ) {
+ $settings = array();
+ }
+ $api_key_raw = isset( $settings['ApiKey'] ) ? $settings['ApiKey'] : '';
+ if ( empty( $api_key_raw ) ) {
+ return $this->rates;
+ }
- $time = (string)time();
- $digits = 3;
- $randId = rand(pow(10, $digits-1), pow(10, $digits)-1);
- $args = array(
- 'sslverify' => false,
- 'httpversion' => '1.1',
- 'timeout' => 30,
- 'redirection' => 0,
- 'compress' => true,
- 'body' => json_encode($finalpackage) ,
- 'headers' => array(
- 'content-type' => 'application/json'
- )
- );
- $headersToSign = array(
- 'X-Shipping-Service-Request-Timestamp' => '' . $time,
- 'X-Shipping-Service-Id' => '' . $randId
- );
- ksort($headersToSign);
+ $getapikey = shiptime_get_consumer_key( $api_key_raw );
-
+ if ( empty( $getapikey ) || empty( $getapikey->consumer_secret ) ) {
+ return $this->rates;
+ }
- $getapikey = get_consumer_key($this->settings['ApiKey']);
+ $encodeHmac = base64_encode(
+ hash_hmac(
+ 'sha256',
+ wp_json_encode( $headersToSign ) . wp_json_encode( $finalpackage ),
+ $getapikey->consumer_secret,
+ true
+ )
+ );
-
-
- $encodeHmac = base64_encode(hash_hmac('sha256', json_encode($headersToSign) . json_encode($finalpackage), $getapikey->consumer_secret, true));
-
- $args['headers']['X-Shipping-Service-Signature'] = $encodeHmac;
-
- $args['headers'] = $args['headers'] + $headersToSign;
- $seturls = array();
- $seturls = get_option( 'woocommerce_shiptime_settings' );
-
- $url = $seturls['liverateUrl'];
-
- if(empty($url))
- {
- return $this->rates;
- }
- $res = wp_remote_post( $url, $args );
+ $args['headers']['X-Shipping-Service-Signature'] = $encodeHmac;
+ $args['headers'] = array_merge( $args['headers'], $headersToSign );
+ $url = isset( $settings['liverateUrl'] ) ? $settings['liverateUrl'] : '';
+ if ( empty( $url ) ) {
+ return $this->rates;
+ }
- // print_r($url);die;
+ $res = wp_remote_post( $url, $args );
+ if ( is_wp_error( $res ) ) {
+ return $this->rates;
+ }
- $getRates = json_decode($res['body']);
+ $body = wp_remote_retrieve_body( $res );
+ $getRates = json_decode( $body );
+ if (
+ empty( $getRates )
+ || empty( $getRates->packages_rates )
+ || empty( $getRates->packages_rates[0]->rates )
+ ) {
+ return $this->rates;
+ }
- foreach ($getRates->packages_rates[0]->rates as $rate) {
- $ratedata = array(
- 'id' => $rate->name,
- 'label' => $rate->name,
- 'cost' => $rate->total_cost,
- 'taxes' => $rate->taxable,
- );
- $this->add_rate( $ratedata );
+ foreach ( $getRates->packages_rates[0]->rates as $rate ) {
+ $this->add_rate( array(
+ 'id' => $rate->name,
+ 'label' => $rate->name,
+ 'cost' => $rate->total_cost,
+ 'taxes' => $rate->taxable,
+ ) );
}
- return $this->rates;
+
+ return $this->rates;
}
-
- private function _prepare_item_data($item)
- {
- $itemData = $item['data'];
-
- /**
- * @var WC_Product $itemData
- */
-
- $data = array(
- 'id' => $itemData->get_id(),
- 'sku' => $itemData->get_sku(),
- 'name' => $itemData->get_name(),
- 'variant_id' => $item['variation_id'] ?: null,
- 'weight' => $itemData->get_weight(),
- 'length' => $itemData->get_length(),
- 'width' => $itemData->get_width(),
- 'height' => $itemData->get_height(),
- 'quantity' => $item['quantity'],
- 'price' => $itemData->get_price(),
- 'subtotal' => $item['line_subtotal'],
- 'subtotal_tax' => $item['line_subtotal_tax'],
- 'total' => $item['line_total'],
- 'total_tax' => $item['line_tax'],
- 'weight_unit' => get_option('woocommerce_weight_unit'),
- );
- $data['additional_fields'] = array(
- 'dimensions_unit' => get_option('woocommerce_dimension_unit'),
- 'height' => $itemData->get_height(),
- 'width' => $itemData->get_width(),
+
+ private function _prepare_item_data( $item ) {
+ $itemData = $item['data'];
+ /** @var WC_Product $itemData */
+
+ $data = array(
+ 'id' => $itemData->get_id(),
+ 'sku' => $itemData->get_sku(),
+ 'name' => $itemData->get_name(),
+ 'variant_id' => $item['variation_id'] ?? null,
+ 'weight' => $itemData->get_weight(),
'length' => $itemData->get_length(),
+ 'width' => $itemData->get_width(),
+ 'height' => $itemData->get_height(),
+ 'quantity' => $item['quantity'],
+ 'price' => $itemData->get_price(),
+ 'subtotal' => $item['line_subtotal'],
+ 'subtotal_tax' => $item['line_subtotal_tax'],
+ 'total' => $item['line_total'],
+ 'total_tax' => $item['line_tax'],
+ 'weight_unit' => get_option( 'woocommerce_weight_unit' ),
);
-
- return $data;
+
+ $data['additional_fields'] = array(
+ 'dimensions_unit' => get_option( 'woocommerce_dimension_unit' ),
+ 'height' => $itemData->get_height(),
+ 'width' => $itemData->get_width(),
+ 'length' => $itemData->get_length(),
+ );
+
+ return $data;
}
}
- }
+ }
}
-
+
add_action( 'woocommerce_shipping_init', 'shiptime_shipping_method' );
-
- function add_shiptime_shipping_method( $methods ) {
+
+ // FIX Line 427: Renamed from add_shiptime_shipping_method -> shiptime_add_shipping_method
+ function shiptime_add_shipping_method( $methods ) {
$methods['shiptime'] = 'ShipTime_Shipping_Method';
return $methods;
}
- add_action('wp_ajax_oauth_st', 'oauth_es_callback');
+ add_filter( 'woocommerce_shipping_methods', 'shiptime_add_shipping_method' );
- function oauth_es_callback()
- {
- /** [[CUSTOM] FOR CONFIGURING .ENV FILE **////////
- /** @desc this loads the composer autoload file */
- require_once 'vendor/autoload.php';
- /** @desc this instantiates Dotenv and passes in our path to .env */
- $dotenv = DotenvDotenv::createImmutable(dirname(__DIR__));
- $dotenv->load();
-
- if($_ENV['SHIPTIME_ENV'] == 'production'){
- $shiptime_api_url = isset( $_ENV['SHIPTIME_PRODUCTION_API_URL'] ) ? $_ENV['SHIPTIME_PRODUCTION_API_URL'] : '' ;
- } else if($_ENV['SHIPTIME_ENV'] == 'staging'){
- $shiptime_api_url = isset( $_ENV['SHIPTIME_STAGING_API_URL'] ) ? $_ENV['SHIPTIME_STAGING_API_URL'] : '' ;
- } else {
- $shiptime_api_url = isset( $_ENV['SHIPTIME_DEVELOPMENT_API_URL'] ) ? $_ENV['SHIPTIME_DEVELOPMENT_API_URL'] : '' ;
+ add_action( 'wp_ajax_oauth_st', 'shiptime_oauth_es_callback' );
+
+ // FIX Line 436: Renamed from oauth_es_callback -> shiptime_oauth_es_callback
+ function shiptime_oauth_es_callback() {
+
+ if ( ! check_ajax_referer( 'shiptime_oauth_nonce', 'nonce', false ) ) {
+ wp_send_json_error( array( 'message' => 'Invalid security token.' ), 403 );
+ }
+
+ if ( ! current_user_can( 'manage_woocommerce' ) ) {
+ wp_send_json_error( array( 'message' => 'Insufficient permissions.' ), 403 );
+ }
+
+ $api_urls = array(
+ 'production' => 'https://app.shiptime.com/directapp',
+ 'staging' => 'https://shiptime.appspaces.ca/directapp',
+ 'development' => 'https://shiptimev3.appspaces.ca/directapp',
+ );
+
+ $env = 'production';
+ $shiptime_api_url = $api_urls[ $env ] ?? $api_urls['production'];
+ $shiptime_platform = 'WoocommerceNativeApi';
+
+ $settings = get_option( 'woocommerce_shiptime_settings', array() );
+ if ( ! is_array( $settings ) ) {
+ $settings = array();
}
- $shiptime_platform = isset( $_ENV['SHIPTIME_PLATFORM'] ) ? $_ENV['SHIPTIME_PLATFORM'] : '' ;
- //////////////////////////////////////////////////
-
- $getApidata = array();
- $getApidata = get_option('woocommerce_shiptime_settings');
- $Apidata = [];
- $Apidata['storeUrl'] = esc_url(site_url());
- $Apidata['apiSecret'] = esc_html($getApidata['ApiKey']);
- $Apidata['platform'] = esc_html($shiptime_platform); //'WoocommerceNativeApi';
- $Apidata['apiUrl'] = esc_url($shiptime_api_url);
-
- echo json_encode($Apidata);
- die;
+ $api_key = $settings['ApiKey'] ?? '';
+
+ if ( empty( $api_key ) ) {
+ wp_send_json_error( array(
+ 'message' => 'ShipTime API key not found. Please save settings first.'
+ ), 400 );
+ }
+
+ $response = array(
+ 'storeUrl' => esc_url( site_url() ),
+ 'apiSecret' => sanitize_text_field( $api_key ),
+ 'platform' => sanitize_text_field( $shiptime_platform ),
+ 'apiUrl' => esc_url( $shiptime_api_url ),
+ );
+
+ wp_send_json_success( $response );
}
- add_filter( 'woocommerce_shipping_methods', 'add_shiptime_shipping_method' );
- function oauth_action_button_st()
- {
+ // FIX Line 478: Renamed from oauth_action_button_st -> shiptime_oauth_action_button
+ function shiptime_oauth_action_button() {
wp_enqueue_script(
- 'oauth_action_button_st',
- plugin_dir_url(__FILE__) . 'includes/assets/js/admin/ajax_oauth_st.js',
- array('jquery'),
- '5.0.4');
+ 'shiptime_oauth_action_button',
+ plugin_dir_url( __FILE__ ) . 'includes/assets/js/admin/ajax_oauth_st.js?'.time(),
+ array( 'jquery' ),
+ '1.1.5',
+ true
+ );
+
+ // Determine connection status: the store is "connected" once ShipTime has
+ // called back and stored a liverateUrl. Pass this flag to JS so the button
+ // can show "Connected" (disabled) instead of "Connect" on page load.
+ $settings = get_option( 'woocommerce_shiptime_settings', array() );
+ $is_connected = ( ! empty( $settings['liverateUrl'] ) ) ? '1' : '0';
+
+ wp_localize_script(
+ 'shiptime_oauth_action_button',
+ 'shiptime_ajax',
+ array(
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
+ 'nonce' => wp_create_nonce( 'shiptime_oauth_nonce' ),
+ 'is_connected' => $is_connected,
+ )
+ );
}
- $shipTimeValues = array();
- $shipTimeValues = get_option( 'woocommerce_shiptime_settings' );
-
- if($shipTimeValues)
- {
- if($shipTimeValues['enabled'] == 'yes')
- {
- add_action('rest_api_init', function () {
- register_rest_route( 'shiptime', '/checkstatus', array(
- 'methods' => 'POST',
- 'callback' => 'newShipstatus'
- ));
- });
-
- add_action('rest_api_init', function () {
- register_rest_route( 'shiptime', '/checkauth', array(
- 'methods' => 'POST',
- 'callback' => 'checkauthenticaton'
- ));
- });
- }
- }
-
- function checkauthenticaton($req)
- {
- $getapiData = get_consumer_key($req['apiKey']);
-
- if(!empty($getapiData)){
- $response['api_keys'] = $req['apiKey'];
- $response['apiSecret'] = $getapiData->consumer_secret;
- }
- else
- {
- $response['error_message'] = 'Invalid ApiKey';
- }
- $res = new WP_REST_Response($response);
- $res->set_status(200);
- if($res->data['error_message'])
- {
- $res->set_status(404);
- }
- return ['req' => $res];
- }
-
- function newShipstatus($req) {
- $response['status'] = $req['status'];
- if($response['status'] === 'true'){
- $response['message'] = 'Connection Successful';
- }
- else
- {
- $response['message'] = 'Connection Error';
- }
- $res = new WP_REST_Response($response);
- if($response['status'] === 'true'){
- $res->set_status(200);
- }else{
- $res->set_status(404);
+
+ $shipTimeValues = get_option( 'woocommerce_shiptime_settings', array() );
+ if ( ! empty( $shipTimeValues ) && isset( $shipTimeValues['enabled'] ) && $shipTimeValues['enabled'] === 'yes' ) {
+
+ add_action( 'rest_api_init', function () {
+
+ register_rest_route( 'shiptime', '/checkstatus', array(
+ 'methods' => 'POST',
+ 'callback' => 'shiptime_new_ship_status',
+ 'permission_callback' => 'shiptime_rest_permission',
+ ) );
+
+ register_rest_route( 'shiptime', '/checkauth', array(
+ 'methods' => 'POST',
+ 'callback' => 'shiptime_check_authentication',
+ 'permission_callback' => 'shiptime_rest_permission',
+ ) );
+
+ } );
+ }
+
+
+ add_action( 'rest_api_init', function () {
+
+ register_rest_route( 'shiptime', '/enableLiverate', array(
+ 'methods' => 'POST',
+ 'callback' => 'shiptime_enable_liverate_url',
+ 'permission_callback' => 'shiptime_rest_permission',
+ 'args' => array(
+ 'liverateUrl' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ 'enable' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ ) );
+
+ register_rest_route( 'shiptime', '/storedelete', array(
+ 'methods' => 'POST',
+ 'callback' => 'shiptime_store_delete',
+ 'permission_callback' => 'shiptime_rest_permission',
+ 'args' => array(
+ 'apiKey' => array(
+ 'required' => true,
+ 'type' => 'string',
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ ) );
+
+ } );
+
+ function shiptime_rest_permission( WP_REST_Request $request ) {
+
+ $api_key = $request->get_param( 'apiKey' );
+
+ if ( ! empty( $api_key ) ) {
+ $api_key = sanitize_text_field( wp_unslash( $api_key ) );
}
+ if ( empty( $api_key ) ) {
+ return false;
+ }
+ $api = shiptime_get_consumer_key( $api_key );
+
+ return ! empty( $api );
+ }
+
+ function shiptime_check_authentication($req) {
+
+ $api_key = sanitize_text_field( $req->get_param( 'apiKey' ) );
+
+ if ( empty( $api_key ) ) {
+ return new WP_REST_Response(
+ array(
+ 'req' => array(
+ 'data' => array(
+ 'error_message' => 'Missing ApiKey'
+ )
+ )
+ ),
+ 400
+ );
+ }
+
+ $getapiData = shiptime_get_consumer_key( $api_key );
+
+ if ( ! empty( $getapiData ) && ! empty( $getapiData->consumer_secret ) ) {
+
+ return new WP_REST_Response(
+ array(
+ 'req' => array(
+ 'data' => array(
+ 'api_keys' => $api_key,
+ 'apiSecret' => $getapiData->consumer_secret,
+ )
+ )
+ ),
+ 200
+ );
+ }
+
+ return new WP_REST_Response(
+ array(
+ 'req' => array(
+ 'data' => array(
+ 'error_message' => 'Invalid ApiKey'
+ )
+ )
+ ),
+ 404
+ );
+ }
+ function shiptime_new_ship_status( WP_REST_Request $req ) {
+
+ $status = sanitize_text_field( $req->get_param( 'status' ) );
+
+ if ( $status === 'true' ) {
+ $message = 'Connection Successful';
+ $status_code = 200;
+ } else {
+ $message = 'Connection Error';
+ $status_code = 404;
+ }
+
global $wpdb;
- $table = $wpdb->prefix.'cart_table';
- $data = array('status' => $res->data['message'],'updatedAt'=>date('Y-m-d H:i:s'));
- $wpdb->insert($table,$data);
- return ['req' => $res];
-
-
- }
- function get_consumer_key( $consumer_key ) {
- global $wpdb;
- $consumer_key = wc_api_hash( sanitize_text_field( $consumer_key ) );
- $api = $wpdb->get_row(
- $wpdb->prepare("
- SELECT key_id, user_id, permissions, consumer_key, consumer_secret, nonces
- FROM {$wpdb->prefix}woocommerce_api_keys
- WHERE consumer_key = %s
- ",
- $consumer_key
- )
- );
- return $api;
+ $table = $wpdb->prefix . 'cart_table';
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
+ $wpdb->insert(
+ $table,
+ array(
+ 'status' => $message,
+ 'updatedAt' => current_time( 'mysql' ),
+ ),
+ array( '%s', '%s' )
+ );
+
+ return new WP_REST_Response(
+ array(
+ 'status' => $status,
+ 'message' => $message,
+ ),
+ $status_code
+ );
+ }
+
+ // FIX Line 617: Renamed from enableLiverateUrl -> shiptime_enable_liverate_url
+ function shiptime_enable_liverate_url( WP_REST_Request $req ) {
+
+ $liverate_url = esc_url_raw( $req->get_param( 'liverateUrl' ) );
+ $enable = sanitize_text_field( $req->get_param( 'enable' ) );
+
+ if ( empty( $liverate_url ) ) {
+ return new WP_REST_Response(
+ array(
+ 'req' => array(
+ 'data' => array(
+ 'error_message' => 'Missing liverateUrl'
+ )
+ )
+ ),
+ 400
+ );
}
+ $liveRateCheckboxValue = ( $enable === 'true' ) ? 'yes' : 'no';
+
+ $seturls = get_option( 'woocommerce_shiptime_settings', array() );
- add_action('rest_api_init', function () {
- register_rest_route( 'shiptime', '/enableLiverate', array(
- 'methods' => 'POST',
- 'callback' => 'enableLiverateUrl'
- ));
- });
-
- function enableLiverateUrl($req)
- {
- $response = array();
- $response['liverateUrl'] = esc_url($req['liverateUrl']);
- $response['enable'] = $req['enable'];
-
- $res = new WP_REST_Response($response);
- if(!empty($res))
- {
- if($response['enable'] == 'true')
- {
- $liveRateCheckboxValue = 'yes';
- }
- else
- {
- $liveRateCheckboxValue = 'no';
- }
- $seturls = array();
- $seturls = get_option( 'woocommerce_shiptime_settings' );
- $seturls['liverateUrl'] = esc_url($response['liverateUrl']);
+ if ( ! is_array( $seturls ) ) {
+ $seturls = array();
+ }
+
+ $seturls['liverateUrl'] = $liverate_url;
$seturls['live_rates_enabled'] = $liveRateCheckboxValue;
- update_option('woocommerce_shiptime_settings', $seturls);
- }
- $res->set_status(200);
- return ['req' => $res];
- }
-
- add_action('rest_api_init', function () {
- register_rest_route( 'shiptime', '/storedelete', array(
- 'methods' => 'POST',
- 'callback' => 'storeDelete'
- ));
- });
- function storeDelete($req)
- {
- $getApiKey = $req->get_params();
- $response = array();
- $response['apiKey'] = esc_html($getApiKey['apiKey']);
- $res = new WP_REST_Response($response);
- $setApikeys = array();
- $setApikeys = get_option( 'woocommerce_shiptime_settings' );
-
- if($res->data['apiKey'] == $setApikeys['ApiKey'])
- {
- update_option( 'woocommerce_shiptime_settings',false);
- $res->message = 'Store Delete Successfully';
- $res->set_status(200);
- }
- else
- {
- $res->message = 'ApiKey does not match !';
- $res->set_status(406);
- }
-
-
- return ['req' => $res];
- }
-
- function insert_cart_table_into_db(){
- global $wpdb;
- $charset_collate = $wpdb->get_charset_collate();
- $tablename = $wpdb->prefix."cart_table";
- $sql = "CREATE TABLE $tablename (
- id mediumint(11) NOT NULL AUTO_INCREMENT,
- status varchar(80) NOT NULL,
- updatedAt datetime,
- PRIMARY KEY (id)
- ) $charset_collate;";
-
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
- dbDelta( $sql );
- $is_error = empty( $wpdb->last_error );
- return $is_error;
+
+ update_option( 'woocommerce_shiptime_settings', $seturls );
+
+ return new WP_REST_Response(
+ array(
+ 'req' => array(
+ 'data' => array(
+ 'liverateUrl' => $liverate_url,
+ 'enable' => $enable,
+ 'status' => 'success'
+ )
+ )
+ ),
+ 200
+ );
+ }
+
+ // FIX Line 644: Renamed from storeDelete -> shiptime_store_delete
+ function shiptime_store_delete( WP_REST_Request $req ) {
+
+ $api_key = sanitize_text_field( $req->get_param( 'apiKey' ) );
+ $settings = get_option( 'woocommerce_shiptime_settings', array() );
+
+ if ( ! is_array($settings) ) {
+ $settings = array();
+ }
+
+ $stored_key = $settings['ApiKey'] ?? '';
+
+ if ( $api_key === $stored_key ) {
+
+ $settings['ApiKey'] = '';
+ $settings['enabled'] = 'no';
+
+ // update_option( 'woocommerce_shiptime_settings', $settings );
+ delete_option('woocommerce_shiptime_settings');
+ return new WP_REST_Response(
+ array( 'message' => 'Store Deleted Successfully' ),
+ 200
+ );
+ }
+
+ return new WP_REST_Response(
+ array( 'message' => 'ApiKey does not match.' ),
+ 406
+ );
+ }
+
+
+ // WordPress.DB.DirectDatabaseQuery.DirectQuery and
+ // WordPress.DB.DirectDatabaseQuery.NoCaching warnings.
+ function shiptime_get_consumer_key( $consumer_key ) {
+ global $wpdb;
+ $consumer_key = wc_api_hash( sanitize_text_field( $consumer_key ) );
+
+ $cache_key = 'shiptime_api_key_' . md5( $consumer_key );
+ $cache_group = 'shiptime';
+
+