Warenwirtschaft: Review-Fix — AP-32-Label als Base64 übertragen (Connector 1.5.0)
Die Brücke hätte live nicht funktioniert: Connector 1.4.0 sendete die label_url aus dem per 'deny from all' geschützten DHL-Ordner (403), dazu SSRF-Risiko durch serverseitigen Abruf einer Client-URL und Timeout- Mismatch (20 s Download vs. 5 s WordPress-Default). Der Connector liest die PDF jetzt vom Shop-Dateisystem (realpath-Pinning auf wp-uploads) und sendet sie Base64; storeWpLabel() validiert und speichert ohne Http::get; tote Shop-Link-Fallbacks aus den Views entfernt; Connector-Timeout 30 s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
ddd6dde593
commit
1b9b6adc44
11 changed files with 173 additions and 83 deletions
|
|
@ -3,7 +3,7 @@
|
|||
/**
|
||||
* Plugin Name: PARTNERCENTER API Connector
|
||||
* Description: Connect WooCommerce to PARTNERCENTER API
|
||||
* Version: 1.4.0
|
||||
* Version: 1.5.0
|
||||
* Author: Cross Media Cloud
|
||||
* Author URI: https://www.cross-media-cloud.de
|
||||
* License: GNU General Public License v2 or later
|
||||
|
|
|
|||
|
|
@ -45,8 +45,11 @@ trait PARTNERCENTER_API_Methods
|
|||
$url = $this->build_url($endpoint);
|
||||
|
||||
// Return the POST request responds
|
||||
// (timeout raised from the 5s WordPress default since 1.5.0 -
|
||||
// order transfers may carry a base64 encoded DHL label)
|
||||
return wp_safe_remote_post($url, [
|
||||
'blocking' => true,
|
||||
'timeout' => 30,
|
||||
'headers' => $this->get_headers(),
|
||||
'body' => json_encode($body),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -140,7 +140,10 @@ trait PARTNERCENTER_API_Order
|
|||
/**
|
||||
* Helper to read the DHL label data saved by the "DHL for WooCommerce" plugin.
|
||||
*
|
||||
* The plugin stores label URL and tracking number(s) as order meta.
|
||||
* The plugin stores label path/URL and tracking number(s) as order meta.
|
||||
* Since 1.5.0 the label FILE is sent base64 encoded (wp_label_pdf): the
|
||||
* label folder inside wp-uploads is protected by "deny from all", so the
|
||||
* PARTNERCENTER could never fetch the raw label_url server side.
|
||||
*
|
||||
* @return array Empty array when no label exists yet
|
||||
*
|
||||
|
|
@ -153,15 +156,69 @@ trait PARTNERCENTER_API_Order
|
|||
$label_meta = $this->order->get_meta('_pr_shipment_dhl_label_tracking');
|
||||
|
||||
// Check if a label was created for this order
|
||||
if (! is_array($label_meta) || empty($label_meta['label_url'])) {
|
||||
if (! is_array($label_meta) || (empty($label_meta['label_path']) && empty($label_meta['tracking_number']))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
'wp_label_url' => $label_meta['label_url'],
|
||||
$label_data = [
|
||||
// String or array (multi parcel) - the API accepts both
|
||||
'wp_tracking_number' => isset($label_meta['tracking_number']) ? $label_meta['tracking_number'] : null,
|
||||
];
|
||||
|
||||
// Read the label file from disk and send it along (base64)
|
||||
$label_pdf = $this->read_label_file(isset($label_meta['label_path']) ? $label_meta['label_path'] : '');
|
||||
if ($label_pdf !== false) {
|
||||
$label_data['wp_label_pdf'] = $label_pdf;
|
||||
}
|
||||
|
||||
// Reference only - the API stores it as origin metadata, it is never fetched
|
||||
if (! empty($label_meta['label_url'])) {
|
||||
$label_data['wp_label_url'] = $label_meta['label_url'];
|
||||
}
|
||||
|
||||
return $label_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a DHL label PDF from disk and return it base64 encoded.
|
||||
*
|
||||
* Only PDF files inside the wp-uploads directory are accepted - the
|
||||
* label_path comes from order meta, never from user input, but we
|
||||
* validate anyway before touching the filesystem.
|
||||
*
|
||||
* @param string $label_path Absolute path from the DHL label meta
|
||||
* @return string|bool Base64 string or false when unreadable/invalid
|
||||
*
|
||||
* @since 1.5.0
|
||||
*/
|
||||
private function read_label_file($label_path)
|
||||
{
|
||||
|
||||
// No label file saved (tracking-only meta)
|
||||
if (empty($label_path) || ! is_string($label_path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve and pin the file to the uploads directory
|
||||
$real_path = realpath($label_path);
|
||||
$uploads = wp_get_upload_dir();
|
||||
$uploads_base = realpath($uploads['basedir']);
|
||||
if ($real_path === false || $uploads_base === false || strpos($real_path, $uploads_base) !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only PDF files
|
||||
if (strtolower(substr($real_path, -4)) !== '.pdf') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read and verify the content really is a PDF
|
||||
$contents = file_get_contents($real_path);
|
||||
if ($contents === false || substr($contents, 0, 4) !== '%PDF') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return base64_encode($contents);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue