Issues (850)

Security Analysis    4 potential vulnerabilities

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection (1)
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection (2)
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting (1)
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

gateways/class-getpaid-worldpay-gateway.php (2 issues)

Severity
1
<?php
2
/**
3
 * Worldpay payment gateway
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Worldpay Payment Gateway class.
11
 *
12
 */
13
class GetPaid_Worldpay_Gateway extends GetPaid_Payment_Gateway {
14
15
    /**
16
	 * Payment method id.
17
	 *
18
	 * @var string
19
	 */
20
    public $id = 'worldpay';
21
22
    /**
23
	 * Payment method order.
24
	 *
25
	 * @var int
26
	 */
27
    public $order = 5;
28
29
    /**
30
	 * Endpoint for requests from Worldpay.
31
	 *
32
	 * @var string
33
	 */
34
	protected $notify_url;
35
36
	/**
37
	 * Endpoint for requests to Worldpay.
38
	 *
39
	 * @var string
40
	 */
41
    protected $endpoint;
42
43
    /**
44
	 * An array of features that this gateway supports.
45
	 *
46
	 * @var array
47
	 */
48
    protected $supports = array( 'sandbox' );
49
50
    /**
51
	 * Currencies this gateway is allowed for.
52
	 *
53
	 * @var array
54
	 */
55
	public $currencies = array( 'AUD', 'ARS', 'CAD', 'CHF', 'DKK', 'EUR', 'HKD', 'MYR', 'GBP', 'NZD', 'NOK', 'SGD', 'LKR', 'SEK', 'TRY', 'USD', 'ZAR' );
56
57
    /**
58
	 * URL to view a transaction.
59
	 *
60
	 * @var string
61
	 */
62
    public $view_transaction_url = 'https://www.{sandbox}paypal.com/activity/payment/%s';
63
64
    /**
65
	 * URL to view a subscription.
66
	 *
67
	 * @var string
68
	 */
69
	public $view_subscription_url = 'https://www.{sandbox}paypal.com/cgi-bin/webscr?cmd=_profile-recurring-payments&encrypted_profile_id=%s';
70
71
    /**
72
	 * Class constructor.
73
	 */
74
	public function __construct() {
75
76
        $this->method_title         = __( 'Worldpay', 'invoicing' );
77
        $this->title                = __( 'Worldpay - Credit Card / Debit Card', 'invoicing' );
78
        $this->checkout_button_text = __( 'Proceed to Worldpay', 'invoicing' );
79
        $this->notify_url           = wpinv_get_ipn_url( $this->id );
80
81
        add_filter( 'wpinv_gateway_description', array( $this, 'sandbox_notice' ), 10, 2 );
82
        add_filter( 'getpaid_worldpay_args', array( $this, 'hash_args' ) );
83
84
        parent::__construct();
85
    }
86
87
    /**
88
	 * Process Payment.
89
	 *
90
	 *
91
	 * @param WPInv_Invoice $invoice Invoice.
92
	 * @param array $submission_data Posted checkout fields.
93
	 * @param GetPaid_Payment_Form_Submission $submission Checkout submission.
94
	 * @return array
95
	 */
96
	public function process_payment( $invoice, $submission_data, $submission ) {
97
98
        // Get redirect url.
99
        $worldpay_redirect = esc_url( $this->get_request_url( $invoice ) );
100
101
        // Get submission args.
102
        $worldpay_args     = $this->get_worldpay_args( $invoice );
103
104
        $form = "<form action='$worldpay_redirect' name='wpi_worldpay_form' method='POST'>";
105
106
        foreach ( $worldpay_args as $key => $value ) {
107
108
            if ( false === $value || '' === trim( $value ) ) {
109
                continue;
110
            }
111
112
            $value = esc_attr( $value );
113
            $key   = wpinv_clean( $key );
114
            $form .= "<input type='hidden' name='$key' value='$value'>";
115
        }
116
117
        $form .= '</form>';
118
119
        wp_send_json_success(
120
            array(
121
                'action' => 'auto_submit_form',
122
                'form'   => $form,
123
            )
124
        );
125
126
        exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
127
128
    }
129
130
    /**
131
	 * Get the Worldpay request URL for an invoice.
132
	 *
133
	 * @param  WPInv_Invoice $invoice Invoice object.
134
	 * @return string
135
	 */
136
	public function get_request_url( $invoice ) {
137
138
        // Endpoint for this request
139
		$this->endpoint = $this->is_sandbox( $invoice ) ? 'https://secure-test.worldpay.com/wcc/purchase' : 'https://secure.worldpay.com/wcc/purchase';
140
141
        return $this->endpoint;
142
143
	}
144
145
    /**
146
	 * Get Worldpay Args for passing to Worldpay.
147
	 *
148
	 * @param  WPInv_Invoice $invoice Invoice object.
149
	 * @return array
150
	 */
151
	protected function get_worldpay_args( $invoice ) {
152
153
		return apply_filters(
154
			'getpaid_worldpay_args',
155
			array(
156
                'amount'         => wpinv_sanitize_amount( $invoice->get_total() ), // mandatory
157
                'cartId'         => wpinv_clean( $invoice->get_number() ), // mandatory reference for the item purchased
158
                'currency'       => wpinv_clean( $invoice->get_currency() ), // mandatory
159
                'instId'         => wpinv_clean( $this->get_option( 'instId', '' ) ), // mandatory
160
                'testMode'       => $this->is_sandbox( $invoice ) ? 100 : 0, // mandatory
161
                'name'           => wpinv_clean( $invoice->get_full_name() ),
162
                'address'        => wpinv_clean( $invoice->get_address() ),
163
                'postcode'       => wpinv_clean( $invoice->get_zip() ),
164
                'tel'            => wpinv_clean( $invoice->get_phone() ),
165
                'email'          => sanitize_email( $invoice->get_email() ),
166
                'country'        => wpinv_clean( $invoice->get_country() ),
167
                'desc'           => sprintf( __( 'Payment for invoice %s.', 'invoicing' ), wpinv_clean( $invoice->get_number() ) ),
168
                'MC_description' => sprintf( __( 'Payment for invoice %s.', 'invoicing' ), wpinv_clean( $invoice->get_number() ) ),
169
                'MC_callback'    => esc_url_raw( $this->notify_url ),
170
                'resultfile'     => esc_url_raw( $this->get_return_url( $invoice ) ),
171
                'MC_key'         => wpinv_clean( $invoice->get_key() ),
172
                'MC_invoice_id'  => $invoice->get_id(),
173
                'address1'       => wpinv_clean( $invoice->get_address() ),
174
                'town'           => wpinv_clean( $invoice->get_city() ),
175
                'region'         => wpinv_clean( $invoice->get_state() ),
176
                'amountString'   => wpinv_price( $invoice->get_total(), $invoice->get_currency() ),
177
                'countryString'  => wpinv_clean( wpinv_country_name( $invoice->get_country() ) ),
178
                'compName'       => wpinv_clean( $invoice->get_company() ),
179
            ),
180
			$invoice
181
		);
182
183
    }
184
185
    /**
186
	 * Secures worldpay args with an md5 hash.
187
	 *
188
	 * @param  array $args Gateway args.
189
	 * @return array
190
	 */
191
	public function hash_args( $args ) {
192
193
        $md5_secret = $this->get_option( 'md5_secret' );
194
195
        // Abort if there is no secret.
196
        if ( empty( $md5_secret ) ) {
197
            return $args;
198
        }
199
200
        // Hash the args.
201
        $args['signature'] = md5( "$md5_secret:{$args['instId']}:{$args['amount']}:{$args['currency']}:{$args['cartId']}" );
202
203
        return $args;
204
    }
205
206
    /**
207
	 * Processes ipns and marks payments as complete.
208
	 *
209
	 * @return void
210
	 */
211
	public function verify_ipn() {
212
213
        // Validate the IPN.
214
        if ( empty( $_POST ) || ! $this->validate_ipn() ) {
215
		    wp_die( 'Worldpay IPN Request Failure', 'Worldpay IPN', array( 'response' => 500 ) );
216
		}
217
218
        // Process the IPN.
219
        $posted  = wp_kses_post_deep( wp_unslash( $_POST ) );
220
        $invoice = wpinv_get_invoice( $posted['MC_invoice_id'] );
221
222
        if ( $invoice && $this->id == $invoice->get_gateway() ) {
223
224
            wpinv_error_log( 'Found invoice #' . $invoice->get_number() );
225
            wpinv_error_log( 'Payment status:' . $posted['transStatus'] );
226
227
            // Update the transaction id.
228
            if ( ! empty( $posted['transId'] ) ) {
229
                $invoice->set_transaction_id( wpinv_clean( $posted['transId'] ) );
230
            }
231
232
             // Update the ip address.
233
             if ( ! empty( $posted['ipAddress'] ) ) {
234
                $invoice->set_ip( wpinv_clean( $posted['ipAddress'] ) );
235
            }
236
237
            if ( $posted['transStatus'] == 'Y' ) {
238
                $invoice->set_completed_date( date( 'Y-m-d H:i:s', $posted['transTime'] ) );
239
                $invoice->mark_paid();
240
                return;
241
            }
242
243
            if ( $posted['transStatus'] == 'C' ) {
244
                $invoice->set_status( 'wpi-failed' );
245
                $invoice->add_note( __( 'Payment transaction failed while processing Worldpay payment.', 'invoicing' ), false, false, true );
246
                $invoice->save();
247
                return;
248
            }
249
250
            wpinv_error_log( 'Aborting, Invalid transaction status:' . $posted['transStatus'] );
251
            $invoice->save();
252
253
        }
254
255
        exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
256
257
    }
258
259
    /**
260
	 * Check Worldpay IPN validity.
261
	 */
262
	public function validate_ipn() {
263
264
        wpinv_error_log( 'Validating Worldpay IPN response' );
265
266
        $data = wp_kses_post_deep( wp_unslash( $_POST ) );
267
268
        // Verify installation.
269
        if ( empty( $data['instId'] ) || $data['instId'] != wpinv_clean( $this->get_option( 'instId', '' ) ) ) {
270
            wpinv_error_log( 'Received invalid installation ID from Worldpay IPN' );
271
            return false;
272
        }
273
274
        // Verify invoice.
275
        if ( empty( $data['cartId'] ) || ! wpinv_get_id_by_invoice_number( $data['cartId'] ) ) {
276
            wpinv_error_log( 'Received invalid invoice number from Worldpay IPN' );
277
            return false;
278
        }
279
280
        // (maybe) verify password.
281
        $password = $this->get_option( 'callback_password' );
282
283
        if ( ! empty( $password ) && ( empty( $data['callbackPW'] ) || $password != $data['callbackPW'] ) ) {
284
            wpinv_error_log( 'Received invalid invoice number from Worldpay IPN' );
285
            return false;
286
        }
287
288
        return true;
289
290
    }
291
292
    /**
293
     * Displays a notice on the checkout page if sandbox is enabled.
294
     */
295
    public function sandbox_notice( $description, $gateway ) {
296
        if ( 'worldpay' == $gateway && wpinv_is_test_mode( 'worldpay' ) ) {
297
            $description .= '<br>' . sprintf(
298
                __( 'SANDBOX ENABLED. See the %1$sWorldpay Sandbox Testing Guide%2$s for more details.', 'invoicing' ),
299
                '<a href="https://developer.worldpay.com/docs/wpg/directintegration/abouttesting">',
300
                '</a>'
301
            );
302
        }
303
        return $description;
304
305
    }
306
307
    /**
308
	 * Filters the gateway settings.
309
	 *
310
	 * @param array $admin_settings
311
	 */
312
	public function admin_settings( $admin_settings ) {
313
314
        $currencies = sprintf(
315
            __( 'Supported Currencies: %s', 'invoicing' ),
316
            implode( ', ', $this->currencies )
317
        );
318
319
        $admin_settings['worldpay_active']['desc'] = $admin_settings['worldpay_active']['desc'] . " ($currencies)";
320
        $admin_settings['worldpay_desc']['std']    = __( 'Pay securely via Worldpay using your PayPal account, credit or debit card.', 'invoicing' );
321
322
        $admin_settings['worldpay_instId'] = array(
323
            'type' => 'text',
324
            'id'   => 'worldpay_instId',
325
            'name' => __( 'Installation Id', 'invoicing' ),
326
            'desc' => __( 'Your installation id. Ex: 211616', 'invoicing' ),
327
        );
328
329
        $admin_settings['worldpay_md5_secret'] = array(
330
            'type' => 'text',
331
            'id'   => 'worldpay_md5_secret',
332
            'name' => __( 'MD5 secret', 'invoicing' ),
333
            'desc' => __( 'Optionally enter your MD5 secret here. Next, open your installation settings and ensure that your SignatureFields parameter is set to ', 'invoicing' ) . '<code>instId:amount:currency:cartId</code>',
334
        );
335
336
        $admin_settings['worldpay_callbackPW'] = array(
337
            'type' => 'text',
338
            'id'   => 'worldpay_callbackPW',
339
            'name' => __( 'Payment Response password', 'invoicing' ),
340
            'desc' => __( 'Recommended. Enter your WorldPay response password to validate payment notifications.', 'invoicing' ),
341
        );
342
343
        $admin_settings['worldpay_ipn_url'] = array(
344
            'type'     => 'ipn_url',
345
            'id'       => 'worldpay_ipn_url',
346
            'name'     => __( 'Payment Response URL', 'invoicing' ),
347
            'std'      => $this->notify_url,
348
            'desc'     => __( 'Login to your Worldpay Merchant Interface then enable Payment Response & Shopper Response. Next, go to the Payment Response URL field and enter the above URL.', 'invoicing' ),
349
            'custom'   => 'worldpay',
350
            'readonly' => true,
351
        );
352
353
		return $admin_settings;
354
	}
355
356
}
357