Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-version: ['8.1', '8.2', '8.3']
php-version: ['8.3']
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
Expand Down
7 changes: 7 additions & 0 deletions assets/css/bootstrap.min.css

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions assets/js/bootstrap.bundle.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build-config.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
version: 2.4.1
version: 2.4.2
min_wc_version: 3.4.7
zipname: woo-jtl-connector-
1 change: 1 addition & 0 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
<copy todir="${tmpdir}/dist/woo-jtl-connector/">
<fileset dir="./">
<include name="src/"/>
<include name="assets/"/>
<include name="plugins/jtl/"/>
<include name="vendor/"/>
</fileset>
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
}
],
"require": {
"php": ">=8.1",
"php": ">=8.3",
"jtl/connector": "dev-master",
"symfony/yaml": "^3.4",
"symfony/yaml": "^6.4",
"twbs/bootstrap": "^4.3",
"theiconic/name-parser": "^0.1.1",
"php-units-of-measure/php-units-of-measure": "^2.1",
Expand Down
8 changes: 7 additions & 1 deletion includes/JtlConnector.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<?php

Check warning on line 1 in includes/JtlConnector.php

View workflow job for this annotation

GitHub Actions / status-check

A file should declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it should execute logic with side effects, but should not do both. The first symbol is defined on line 16 and the first side effect is on line 6.

Check warning on line 1 in includes/JtlConnector.php

View workflow job for this annotation

GitHub Actions / status-check

A file should declare new symbols (classes, functions, constants, etc.) and cause no other side effects, or it should execute logic with side effects, but should not do both. The first symbol is defined on line 16 and the first side effect is on line 6.

declare(strict_types=1);

if (!defined('ABSPATH')) {
exit;
}

use Jtl\Connector\Core\Application\Application;
use Jtl\Connector\Core\Config\ConfigSchema;
use Jtl\Connector\Core\Config\FileConfig;
Expand Down Expand Up @@ -43,7 +47,7 @@

if (!\is_string($features)) {
throw new \InvalidArgumentException(
"Expected features to be a string but got " . \gettype($features) . " instead."
\esc_html("Expected features to be a string but got " . \gettype($features) . " instead.")
);
}

Expand All @@ -61,10 +65,12 @@
*/
private static function unslash_gpc(): void //phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
{
// phpcs:disable WordPress.Security.ValidatedSanitizedInput, WordPress.Security.NonceVerification.Recommended -- Intentional: reverse WordPress magic quotes for JTL Connector request processing
$_GET = array_map('stripslashes_deep', $_GET);
$_POST = array_map('stripslashes_deep', $_POST);
$_COOKIE = array_map('stripslashes_deep', $_COOKIE);
$_SERVER = array_map('stripslashes_deep', $_SERVER);
$_REQUEST = array_map('stripslashes_deep', $_REQUEST);
// phpcs:enable
}
}
1,077 changes: 635 additions & 442 deletions includes/JtlConnectorAdmin.php

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,11 @@ parameters:
- './var/*'
ignoreErrors:
- '#Constant WC_DELIMITER not found.#'
- '#PHPDoc tag @throws with type .* is not subtype of Throwable#'
-
message: '#Binary operation "\."\s+between .+ and array\|string results in an error#'
path: includes/JtlConnectorAdmin.php
count: 7
-
message: '#Strict comparison using === between non-empty-string and false will always evaluate to false#'
path: woo-jtl-connector.php
count: 1
22 changes: 15 additions & 7 deletions readme.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
=== JTL-Connector for WooCommerce ===
Contributors: papryk, ntbyk, platzkejtl
Contributors: papryk, ntbyk, platzkejtl, patrick-gugelsberger
Tags: warenwirtschaft, jtl, connector, wms, erp
Requires at least: 4.7
Tested up to: 6.4
Requires PHP: 8.0
WC requires at least: 3.4
WC tested up to: 8.2
Stable tag: 2.4.1
Requires at least: 6.4
Tested up to: 7.0
Requires PHP: 8.3
WC requires at least: 3.4.7
WC tested up to: 10.8.1
Stable tag: 2.4.2
License: GPLv3
License URI: http://www.gnu.org/licenses/lgpl-3.0.html

Expand Down Expand Up @@ -152,6 +152,14 @@ This section describes how to install the plugin and get it working.

== Changelog ==

= 2.4.2 =
* Security: Added capability checks and nonce verification to all admin endpoints (CVE-2026-9234)
* Security: Log download now streams via temporary file instead of writing to public directory
* Fix: Replaced external CDN resources with locally bundled assets
* Fix: Added proper SQL preparation and output escaping throughout the plugin
* Fix: Global functions now use jtlwcc_ prefix to avoid naming conflicts
* Fix: Replaced deprecated PHP functions with WordPress alternatives

Find the newest Changelog here: http://changelog.jtl-software.de/en/systems/connector/woocommerce

== Upgrade Notice ==
Expand Down
2 changes: 1 addition & 1 deletion src/Authentication/TokenValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ public function __construct(string $endpointToken = '')
*/
public function validate(string $token): bool
{
return $token === $this->endpointToken;
return \hash_equals($this->endpointToken, $token);
}
}
4 changes: 1 addition & 3 deletions src/Connector.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

namespace JtlWooCommerceConnector;

\ini_set('display_errors', 'off');

use DI\Container;
use DI\DependencyException;
use DI\NotFoundException;
Expand Down Expand Up @@ -97,7 +95,7 @@ public function initialize(ConfigInterface $config, Container $container, EventD

if (!\is_string($featuresPath)) {
throw new \InvalidArgumentException(
"Expected featuresPath to be string but got " . \gettype($featuresPath) . " instead"
"Expected featuresPath to be string but got " . \esc_html(\gettype($featuresPath)) . " instead"
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Controllers/CategoryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@ public function push(AbstractModel ...$models): array
} else {
$categoryTerm = \get_term($categoryId, CategoryUtil::TERM_TAXONOMY);
if (!$categoryTerm instanceof \WP_Term) {
throw new \Exception(\sprintf("Cannot find category %s", $categoryId));
throw new \Exception(\sprintf("Cannot find category %s", \esc_html((string)$categoryId)));
}
// WordPress does not create a unique slug itself if the given already exists
if ($categoryTerm->slug !== wc_strtolower($categoryData['slug'])) {
if ($categoryTerm->slug !== \wc_strtolower($categoryData['slug'])) {
$categoryData['slug'] = \wp_unique_term_slug($categoryData['slug'], (object)$categoryData);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Controllers/CrossSellingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class CrossSellingController extends AbstractBaseController implements
DeleteInterface,
StatisticInterface
{
public const CROSSSELLING_META_KEY = '_crosssell_ids';
public const UPSELLING_META_KEY = '_upsell_ids';
public const string CROSSSELLING_META_KEY = '_crosssell_ids';
public const string UPSELLING_META_KEY = '_upsell_ids';

/**
* @param QueryFilter $query
Expand Down
10 changes: 5 additions & 5 deletions src/Controllers/CustomerOrderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
class CustomerOrderController extends AbstractBaseController implements PullInterface, StatisticInterface
{
/** Order received (unpaid) */
public const
public const string
STATUS_PENDING = 'pending',
/** Payment received – the order is awaiting fulfillment */
STATUS_PROCESSING = 'processing',
Expand All @@ -41,8 +41,8 @@ class CustomerOrderController extends AbstractBaseController implements PullInte
/** Already paid */
STATUS_REFUNDED = 'refunded';

public const BILLING_ID_PREFIX = 'b_';
public const SHIPPING_ID_PREFIX = 's_';
public const string BILLING_ID_PREFIX = 'b_';
public const string SHIPPING_ID_PREFIX = 's_';

/**
* @param QueryFilter $query
Expand Down Expand Up @@ -178,7 +178,7 @@ protected function setPayPalPlusPaymentInfo(\WC_Order $order, CustomerOrderModel

if (!\is_array($payPalPlusSettings)) {
throw new \InvalidArgumentException(
"payPalSettings expected to be an array but got " . \gettype($payPalPlusSettings)
"payPalSettings expected to be an array but got " . \esc_html(\gettype($payPalPlusSettings))
);
}

Expand All @@ -188,7 +188,7 @@ protected function setPayPalPlusPaymentInfo(\WC_Order $order, CustomerOrderModel

if (!\is_array($orderMetaData)) {
throw new \InvalidArgumentException(
"orderMetaData expected to be an array but got " . \gettype($orderMetaData)
"orderMetaData expected to be an array but got " . \esc_html(\gettype($orderMetaData))
);
}

Expand Down
8 changes: 4 additions & 4 deletions src/Controllers/GlobalData/CurrencyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@

class CurrencyController extends AbstractBaseController
{
public const ISO = 'woocommerce_currency';
public const SIGN_POSITION = 'woocommerce_currency_pos';
public const CENT_DELIMITER = 'woocommerce_price_decimal_sep';
public const THOUSAND_DELIMITER = 'woocommerce_price_thousand_sep';
public const string ISO = 'woocommerce_currency';
public const string SIGN_POSITION = 'woocommerce_currency_pos';
public const string CENT_DELIMITER = 'woocommerce_price_decimal_sep';
public const string THOUSAND_DELIMITER = 'woocommerce_price_thousand_sep';

/**
* @return CurrencyModel[]
Expand Down
5 changes: 3 additions & 2 deletions src/Controllers/GlobalData/CustomerGroupController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

class CustomerGroupController extends AbstractBaseController
{
public const DEFAULT_GROUP = 'customer';
public const string DEFAULT_GROUP = 'customer';

protected Db $db;
protected Util $util;
Expand All @@ -42,6 +42,7 @@ public function pull(): array
->setIsDefault(true);

$defaultI18n = (new CustomerGroupI18n())
// phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Third-party string from WooCommerce
->setName(\__('Customer', 'woocommerce'))
->setLanguageISO($langIso);

Expand Down Expand Up @@ -71,7 +72,7 @@ public function pull(): array

if (!\is_array($meta)) {
throw new \InvalidArgumentException(
"meta expected to be an array but got " . \gettype($meta) . " instead"
"meta expected to be an array but got " . \esc_html(\gettype($meta)) . " instead"
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Controllers/GlobalData/ShippingClassController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

class ShippingClassController extends AbstractBaseController
{
public const TERM_TAXONOMY = 'product_shipping_class';
public const string TERM_TAXONOMY = 'product_shipping_class';

/**
* @return array<int, ShippingClassModel>
Expand Down
9 changes: 4 additions & 5 deletions src/Controllers/GlobalDataController.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,10 @@ public function pull(QueryFilter $query): array
}

if ($hasDefaultCustomerGroup === false) {
throw new Exception(\__(
"The default customer is not set. Please update the B2B-Market default customer group "
. "in the JTL-Connector settings in the Wordpress admin panel.",
\JTLWCC_TEXT_DOMAIN
));
throw new Exception(\esc_html(\__(
'The default customer is not set. Please update the B2B-Market default customer group in the JTL-Connector settings in the Wordpress admin panel.', // phpcs:ignore Generic.Files.LineLength.TooLong
'woo-jtl-connector'
)));
}

// if (Config::get(Config::OPTIONS_AUTO_WOOCOMMERCE_OPTIONS)) {
Expand Down
31 changes: 17 additions & 14 deletions src/Controllers/ImageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ class ImageController extends AbstractBaseController implements
PushInterface,
DeleteInterface
{
public const GALLERY_DIVIDER = ',';
public const PRODUCT_THUMBNAIL = '_thumbnail_id';
public const CATEGORY_THUMBNAIL = 'thumbnail_id';
public const GALLERY_KEY = '_product_image_gallery';
public const MANUFACTURER_KEY = 'pwb_brand_image';
public const PRODUCT_IMAGE = 'product';
public const CATEGORY_IMAGE = 'category';
public const MANUFACTURER_IMAGE = 'manufacturer';
public const string GALLERY_DIVIDER = ',';
public const string PRODUCT_THUMBNAIL = '_thumbnail_id';
public const string CATEGORY_THUMBNAIL = 'thumbnail_id';
public const string GALLERY_KEY = '_product_image_gallery';
public const string MANUFACTURER_KEY = 'pwb_brand_image';
public const string PRODUCT_IMAGE = 'product';
public const string CATEGORY_IMAGE = 'category';
public const string MANUFACTURER_IMAGE = 'manufacturer';

/** @var array<int, int|string> */
private array $alreadyLinked = [];
Expand Down Expand Up @@ -139,7 +139,7 @@ private function addNextImages(array $images, int $type, int $limit): array
$model = new ManufacturerImage();
break;
default:
throw new Exception(\sprintf("Invalid image type '%s'", $type));
throw new Exception(\sprintf("Invalid image type '%s'", \esc_html((string)$type)));
}

$model->setId(new Identity($imageLinkId))
Expand Down Expand Up @@ -208,7 +208,7 @@ private function productImagePull(?int $limit = null): array

if (!\is_int($postId)) {
throw new \InvalidArgumentException(
"Expected postId to be an integer but got " . \gettype($postId) . " instead."
"Expected postId to be an integer but got " . \esc_html(\gettype($postId)) . " instead."
);
}

Expand Down Expand Up @@ -398,7 +398,7 @@ private function categoryImagePullByQuery(string $query): array

if (!\is_array($images)) {
throw new \InvalidArgumentException(
"Expected images to be an array but got " . \gettype($images) . " instead."
"Expected images to be an array but got " . \esc_html(\gettype($images)) . " instead."
);
}

Expand Down Expand Up @@ -697,7 +697,10 @@ protected function relinkImage(int $newEndpointId, AbstractImage $image): void
$type = IdentityType::CATEGORY_IMAGE;
break;
default:
throw new \Exception(\sprintf('Relation type %s is not supported.', $image->getRelationType()));
throw new \Exception(\sprintf(
'Relation type %s is not supported.',
\esc_html($image->getRelationType())
));
}

$primaryKeyMapper->delete(
Expand Down Expand Up @@ -982,8 +985,8 @@ private function deleteImageTermMeta(AbstractImage $image, bool $realDelete): vo
throw new RuntimeException(
\sprintf(
"Invalid relation %s type for id %s when deleting image.",
$image->getRelationType(),
$endpointId
\esc_html($image->getRelationType()),
\esc_html($endpointId)
)
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Controllers/ManufacturerController.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class ManufacturerController extends AbstractBaseController implements
DeleteInterface,
StatisticInterface
{
public const TAXONOMY_PERFECT_BRANDS = 'pwb-brand';
public const TAXONOMY_GERMANIZED = 'product_manufacturer';
public const string TAXONOMY_PERFECT_BRANDS = 'pwb-brand';
public const string TAXONOMY_GERMANIZED = 'product_manufacturer';

/** @var array<int, int> */
private static array $idCache = [];
Expand Down
2 changes: 1 addition & 1 deletion src/Controllers/Order/CustomerOrderItemController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

class CustomerOrderItemController extends AbstractBaseController
{
public const PRICE_DECIMALS = 4;
public const int PRICE_DECIMALS = 4;

/** @var array<int|string, float> $taxRateCache Map tax rate id to tax rate */
protected static array $taxRateCache = [];
Expand Down
13 changes: 7 additions & 6 deletions src/Controllers/PaymentController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Jtl\Connector\Core\Model\Payment as PaymentModel;
use Jtl\Connector\Core\Model\QueryFilter;
use Jtl\Connector\Core\Definition\PaymentType;
use JtlWooCommerceConnector\Utilities\LinkTableNames;
use JtlWooCommerceConnector\Utilities\SqlHelper;
use JtlWooCommerceConnector\Utilities\Util;
use Psr\Log\InvalidArgumentException;
Expand All @@ -26,7 +27,7 @@
*/
class PaymentController extends AbstractBaseController implements PullInterface, PushInterface, StatisticInterface
{
public const PAY_UPON_INVOICE = 'PAY_UPON_INVOICE';
public const string PAY_UPON_INVOICE = 'PAY_UPON_INVOICE';

/**
* @param QueryFilter $query
Expand Down Expand Up @@ -78,11 +79,11 @@ public function pull(QueryFilter $query): array
*/
public function getOrderHostId(int $endpointId): int
{
$query = \sprintf(
"Select host_id from %sjtl_connector_link_order where endpoint_id = %s",
$this->db->getWpDb()->prefix,
$endpointId
);
/** @var string $table */
$table = \esc_sql($this->db->getWpDb()->prefix . LinkTableNames::ORDER);
/** @var literal-string $sql */
$sql = "Select host_id from `{$table}` where endpoint_id = %d";
$query = (string)$this->db->getWpDb()->prepare($sql, $endpointId);

return (int)$this->db->queryOne($query);
}
Expand Down
Loading
Loading