diff --git a/Payment/LiqPay.php b/Payment/LiqPay.php new file mode 100644 index 0000000..b6f3e4e --- /dev/null +++ b/Payment/LiqPay.php @@ -0,0 +1,208 @@ +paymentProfile->options; + + $payment = [ + 'version' => 3, + 'public_key' => $profileOptions['public_key'], + 'action' => 'pay', + 'amount' => $purchase->cost, + 'currency' => $purchase->currency, + 'description' => $purchase->title, + 'order_id' => $purchaseRequest->request_key, + + 'result_url' => $purchase->returnUrl, + 'server_url' => $this->getCallbackUrl(), + ]; + + return $this->getDataAndSignature($payment, $profileOptions['private_key']); + } + + public function initiatePayment(Controller $controller, PurchaseRequest $purchaseRequest, Purchase $purchase): XF\Mvc\Reply\Redirect + { + $paymentParams = $this->getPaymentParams($purchaseRequest, $purchase); + + return $controller->redirect($this->getApiEndpoint() . '?' . http_build_query($paymentParams)); + } + + public function setupCallback(Request $request): CallbackState + { + $state = new CallbackState(); + + $state->dataRaw = $request->filter('data', 'str'); + $state->data = json_decode(base64_decode($state->dataRaw), true); + $state->signature = $request->filter('signature', 'str'); + + $state->amount = $state->data['amount'] ?? 0; + $state->currency = $state->data['currency'] ?? ''; + $state->status = $state->data['status'] ?? ''; + $state->subscriberId = $state->data['customer'] ?? 0; + + $state->ip = $request->getIp(); + + $state->httpCode = 200; + + return $state; + } + + public function validateCallback(CallbackState $state): bool + { + $state->requestKey = $state->data['order_id'] ?? ''; + $state->transactionId = $state->input['payment_id'] ?? ''; + + if (!empty($state->signature) && $state->data['version'] == 3 && $state->data['action'] == 'pay') + { + return true; + } + + $state->logType = 'info'; + $state->logMessage = 'Auth failed'; + + return false; + } + + public function validateTransaction(CallbackState $state): bool + { + if (!$state->requestKey) + { + $state->logType = 'info'; + $state->logMessage = 'Metadata is empty!'; + + return false; + } + + if(!empty($state->data['err_code'])) + { + $state->logType = 'error'; + $state->logMessage = $state->data['err_description'] ?? $state->data['err_code']; + + return false; + } + + return parent::validateTransaction($state); + } + + public function validatePurchasableData(CallbackState $state): bool + { + $paymentProfile = $state->getPaymentProfile(); + + $options = $paymentProfile->options; + if (!empty($options['public_key']) && !empty($options['private_key']) && !empty($state->signature)) + { + if ($this->verifySignature($state->dataRaw, $state->signature, $options['private_key'])) + { + return true; + } + + $state->logType = 'error'; + $state->logMessage = "Invalid signature"; + + return false; + } + + $state->logType = 'error'; + $state->logMessage = 'Invalid public_key or secret_key.'; + + return false; + } + + public function validateCost(CallbackState $state): bool + { + $purchaseRequest = $state->getPurchaseRequest(); + + if (($state->currency == $purchaseRequest->cost_currency) + && round($state->amount, 2) == round($purchaseRequest->cost_amount, 2)) + { + return true; + } + + $state->logType = 'error'; + $state->logMessage = 'Invalid cost amount.'; + + return false; + } + + public function getPaymentResult(CallbackState $state): void + { + if (strtolower($state->status) == 'success') + { + $state->paymentResult = CallbackState::PAYMENT_RECEIVED; + } + } + + public function prepareLogData(CallbackState $state): void + { + $state->logDetails = array_merge($state->data, [ + 'ip' => $state->ip, + 'signature' => $state->signature + ]); + } + + public function verifyCurrency(PaymentProfile $paymentProfile, $currencyCode): bool + { + return in_array($currencyCode, $this->supportedCurrencies); + } + + protected $supportedCurrencies = [ + 'RUB', 'USD', 'EUR', 'UAH', 'BYN', 'KZT' + ]; + + public function supportsRecurring(PaymentProfile $paymentProfile, $unit, $amount, &$result = self::ERR_NO_RECURRING): bool + { + $result = self::ERR_NO_RECURRING; + + return false; + } + + protected function getDataAndSignature(array $payment, string $privateKey): array + { + $data = base64_encode(json_encode($payment)); + $signature = base64_encode(hash('sha1', $privateKey . $data . $privateKey, true)); + + return [ + 'data' => $data, + 'signature' => $signature + ]; + } + + protected function verifySignature(string $data, string $signature, string $privateKey): bool + { + return hash_equals($signature, base64_encode(hash('sha1', $privateKey . $data . $privateKey, true))); + } +} \ No newline at end of file diff --git a/Setup.php b/Setup.php new file mode 100644 index 0000000..41567c6 --- /dev/null +++ b/Setup.php @@ -0,0 +1,34 @@ +db(); + + $db->insert('xf_payment_provider', [ + 'provider_id' => "wh1LiqPay", + 'provider_class' => "WH1\\PaygateLiqPay:LiqPay", + 'addon_id' => "WH1/PaygateLiqPay" + ]); + } + + public function uninstallStep1() + { + $db = $this->db(); + + $db->delete('xf_payment_profile', "provider_id = 'wh1LiqPay'"); + $db->delete('xf_payment_provider', "provider_id = 'wh1LiqPay'"); + } +} \ No newline at end of file diff --git a/_data/activity_summary_definitions.xml b/_data/activity_summary_definitions.xml new file mode 100644 index 0000000..a55af11 --- /dev/null +++ b/_data/activity_summary_definitions.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/admin_navigation.xml b/_data/admin_navigation.xml new file mode 100644 index 0000000..8aa506b --- /dev/null +++ b/_data/admin_navigation.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/admin_permission.xml b/_data/admin_permission.xml new file mode 100644 index 0000000..67760e7 --- /dev/null +++ b/_data/admin_permission.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/advertising_positions.xml b/_data/advertising_positions.xml new file mode 100644 index 0000000..32059fa --- /dev/null +++ b/_data/advertising_positions.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/api_scopes.xml b/_data/api_scopes.xml new file mode 100644 index 0000000..3510b36 --- /dev/null +++ b/_data/api_scopes.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/bb_code_media_sites.xml b/_data/bb_code_media_sites.xml new file mode 100644 index 0000000..bdf7d27 --- /dev/null +++ b/_data/bb_code_media_sites.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/bb_codes.xml b/_data/bb_codes.xml new file mode 100644 index 0000000..8c337bf --- /dev/null +++ b/_data/bb_codes.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/class_extensions.xml b/_data/class_extensions.xml new file mode 100644 index 0000000..bd0ad9f --- /dev/null +++ b/_data/class_extensions.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/code_event_listeners.xml b/_data/code_event_listeners.xml new file mode 100644 index 0000000..a9a91ea --- /dev/null +++ b/_data/code_event_listeners.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/code_events.xml b/_data/code_events.xml new file mode 100644 index 0000000..7752d3e --- /dev/null +++ b/_data/code_events.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/content_type_fields.xml b/_data/content_type_fields.xml new file mode 100644 index 0000000..3040a1f --- /dev/null +++ b/_data/content_type_fields.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/cron.xml b/_data/cron.xml new file mode 100644 index 0000000..b45f056 --- /dev/null +++ b/_data/cron.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/help_pages.xml b/_data/help_pages.xml new file mode 100644 index 0000000..31828b1 --- /dev/null +++ b/_data/help_pages.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/member_stats.xml b/_data/member_stats.xml new file mode 100644 index 0000000..a80a38b --- /dev/null +++ b/_data/member_stats.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/navigation.xml b/_data/navigation.xml new file mode 100644 index 0000000..752ce9a --- /dev/null +++ b/_data/navigation.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/option_groups.xml b/_data/option_groups.xml new file mode 100644 index 0000000..b453ed4 --- /dev/null +++ b/_data/option_groups.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/options.xml b/_data/options.xml new file mode 100644 index 0000000..140bd10 --- /dev/null +++ b/_data/options.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/permission_interface_groups.xml b/_data/permission_interface_groups.xml new file mode 100644 index 0000000..87ad617 --- /dev/null +++ b/_data/permission_interface_groups.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/permissions.xml b/_data/permissions.xml new file mode 100644 index 0000000..16b1408 --- /dev/null +++ b/_data/permissions.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/phrases.xml b/_data/phrases.xml new file mode 100644 index 0000000..8c2b1c0 --- /dev/null +++ b/_data/phrases.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/_data/routes.xml b/_data/routes.xml new file mode 100644 index 0000000..608d809 --- /dev/null +++ b/_data/routes.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/style_properties.xml b/_data/style_properties.xml new file mode 100644 index 0000000..231b9f0 --- /dev/null +++ b/_data/style_properties.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/style_property_groups.xml b/_data/style_property_groups.xml new file mode 100644 index 0000000..563c56d --- /dev/null +++ b/_data/style_property_groups.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/template_modifications.xml b/_data/template_modifications.xml new file mode 100644 index 0000000..04c9d33 --- /dev/null +++ b/_data/template_modifications.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/templates.xml b/_data/templates.xml new file mode 100644 index 0000000..e9181db --- /dev/null +++ b/_data/templates.xml @@ -0,0 +1,12 @@ + + + + diff --git a/_data/widget_definitions.xml b/_data/widget_definitions.xml new file mode 100644 index 0000000..fbdae64 --- /dev/null +++ b/_data/widget_definitions.xml @@ -0,0 +1,2 @@ + + diff --git a/_data/widget_positions.xml b/_data/widget_positions.xml new file mode 100644 index 0000000..65d80ac --- /dev/null +++ b/_data/widget_positions.xml @@ -0,0 +1,2 @@ + + diff --git a/addon.json b/addon.json new file mode 100644 index 0000000..8eeefea --- /dev/null +++ b/addon.json @@ -0,0 +1,23 @@ +{ + "legacy_addon_id": "", + "title": "[WH1] Paygate: LiqPay", + "description": "LiqPay payment profile for XenForo.", + "version_id": 1000070, + "version_string": "1.0.0", + "dev": "wh1teend", + "dev_url": "https://t.me/wh1teend", + "faq_url": "", + "support_url": "", + "extra_urls": [], + "require": { + "php": [ + "7.4", + "PHP 7.4+" + ], + "XF": [ + 2010270, + "XenForo 2.1.2+" + ] + }, + "icon": "icon.png" +} \ No newline at end of file diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..6033398 Binary files /dev/null and b/icon.png differ