<?xml version="1.0" encoding="utf-8"?>
<modification>
    <name>DearSoft Anti-Spam Order Guard</name>
    <code>dearsoft_antispam_orders</code>
    <version>1.1.0</version>
    <author>DearSoft</author>
    <link>https://dev.deargroup.co</link>

    <!--
        Rate-limits at the exact moment a Cash On Delivery order gets
        CONFIRMED (order_status transitions from draft/0 to a real status) -
        not at Journal3's continuous checkout-step auto-save, which creates/
        updates a draft order row on every address/shipping-method change and
        would falsely trip a limit for a normal customer filling out the
        checkout form. This only fires once, when the customer actually
        finalizes the order.

        Threshold: 3 confirmed orders from the same IP within 10 minutes.
        Adjust the "3" / "10 MINUTE" below if this proves too strict/loose
        in practice.
    -->
    <file path="catalog/controller/extension/payment/cod.php">
        <operation>
            <search trim="true"><![CDATA[if (isset($this->session->data['payment_method']['code']) && $this->session->data['payment_method']['code'] == 'cod') {]]></search>
            <add position="after"><![CDATA[
			$dearsoft_antispam_ip = $this->request->server['REMOTE_ADDR'];
			$dearsoft_antispam_check = $this->db->query("SELECT COUNT(*) AS cnt FROM `" . DB_PREFIX . "order` WHERE ip = '" . $this->db->escape($dearsoft_antispam_ip) . "' AND date_added > DATE_SUB(NOW(), INTERVAL 10 MINUTE) AND order_status_id > 0");
			if ($dearsoft_antispam_check->row['cnt'] >= 3) {
				$json['error'] = 'Too many orders placed recently from this connection. Please wait a few minutes and try again, or contact us directly.';
				$this->response->addHeader('Content-Type: application/json');
				$this->response->setOutput(json_encode($json));
				return;
			}
]]></add>
        </operation>
    </file>

    <!--
        1.1.0: two checkout-form changes on the same site's Journal3 quick
        checkout (catalog/controller/journal3/checkout.php):

        (a) Email is made optional for GUEST checkout (still validated for
            format if the shopper does type one, and still required+checked-
            for-duplicates when actually creating an account, since a login
            needs a real email). Telephone was already required by this
            theme's own default (quickCheckoutAccountTelephoneField, see
            system/library/journal3/data/settings/skin/page/checkout.json) -
            no change needed there.

        (b) Registration rate-limit: blocks creating more than 2 new customer
            accounts from the same IP within 30 minutes - this is what would
            have caught the earlier incident where two accounts were created
            13 minutes apart from the same IP/phone number and both landed
            with a broken customer_id.
    -->
    <file path="catalog/controller/journal3/checkout.php">
        <operation>
            <search trim="true"><![CDATA[// email
		if ((utf8_strlen(Arr::get($this->request->post, 'order_data.email')) > 96) || !filter_var(Arr::get($this->request->post, 'order_data.email'), FILTER_VALIDATE_EMAIL)) {
			$error['email'] = $this->language->get('error_email');
		} else if (($this->session->data['account'] === 'register') && $this->model_account_customer->getTotalCustomersByEmail(Arr::get($this->request->post, 'order_data.email'))) {
			$error['email'] = $this->language->get('error_exists');
		}]]></search>
            <add position="replace"><![CDATA[// email — optional for guest checkout; still required+validated when
		// actually registering an account, since login needs a real email.
		$dearsoft_email_value = Arr::get($this->request->post, 'order_data.email');
		if ($this->session->data['account'] === 'register' || $dearsoft_email_value !== '') {
			if ((utf8_strlen($dearsoft_email_value) > 96) || !filter_var($dearsoft_email_value, FILTER_VALIDATE_EMAIL)) {
				$error['email'] = $this->language->get('error_email');
			} else if (($this->session->data['account'] === 'register') && $this->model_account_customer->getTotalCustomersByEmail($dearsoft_email_value)) {
				$error['email'] = $this->language->get('error_exists');
			}
		}]]></add>
        </operation>

        <operation>
            <search trim="true"><![CDATA[// passwords
		if ($this->session->data['account'] === 'register') {]]></search>
            <add position="after"><![CDATA[
			$dearsoft_reg_ip = $this->request->server['REMOTE_ADDR'];
			$dearsoft_reg_check = $this->db->query("SELECT COUNT(*) AS cnt FROM " . DB_PREFIX . "customer WHERE ip = '" . $this->db->escape($dearsoft_reg_ip) . "' AND date_added > DATE_SUB(NOW(), INTERVAL 30 MINUTE)");
			if ($dearsoft_reg_check->row['cnt'] >= 2) {
				$error['email'] = 'Too many accounts created recently from this connection. Please wait a while and try again, or continue as a guest.';
			}
]]></add>
        </operation>
    </file>

</modification>
